hiera 1.2.1 → 1.3.0.rc2

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of hiera might be problematic. Click here for more details.

data/README.md CHANGED
@@ -117,7 +117,7 @@ A sample configuration file can be seen here:
117
117
  :logger: console
118
118
 
119
119
  :hierarchy:
120
- - "%{location}"
120
+ - "sites/%{location}"
121
121
  - common
122
122
 
123
123
  :yaml:
@@ -130,14 +130,14 @@ A sample configuration file can be seen here:
130
130
  This configuration will require YAML files in _/etc/puppet/hieradata_ these need to contain
131
131
  Hash data, sample files matching the hierarchy described in the _Why?_ section are below:
132
132
 
133
- _/etc/puppet/hieradata/dc1.yaml_:
133
+ _/etc/puppet/hieradata/sites/dc1.yaml_:
134
134
  <pre>
135
135
  ---
136
136
  ntpserver: ntp1.dc1.example.com
137
137
  sysadmin: dc1noc@example.com
138
138
  </pre>
139
139
 
140
- _/etc/puppet/hieradata/dc2.yaml_:
140
+ _/etc/puppet/hieradata/sites/dc2.yaml_:
141
141
  <pre>
142
142
  ---
143
143
  ntpserver: ntp1.dc2.example.com
data/bin/hiera CHANGED
@@ -24,6 +24,7 @@ end
24
24
  require 'hiera'
25
25
  require 'hiera/util'
26
26
  require 'optparse'
27
+ require 'pp'
27
28
 
28
29
  options = {
29
30
  :default => nil,
@@ -222,5 +223,5 @@ ans = hiera.lookup(options[:key], options[:default], options[:scope], nil, optio
222
223
  if ans.is_a?(String)
223
224
  puts ans
224
225
  else
225
- p ans
226
+ pp ans
226
227
  end
@@ -1,8 +1,8 @@
1
1
  require 'yaml'
2
2
 
3
3
  class Hiera
4
- VERSION = "1.2.1"
5
-
4
+ require "hiera/error"
5
+ require "hiera/version"
6
6
  require "hiera/config"
7
7
  require "hiera/util"
8
8
  require "hiera/backend"
@@ -15,10 +15,6 @@ class Hiera
15
15
  class << self
16
16
  attr_reader :logger
17
17
 
18
- def version
19
- VERSION
20
- end
21
-
22
18
  # Loggers are pluggable, just provide a class called
23
19
  # Hiera::Foo_logger and respond to :warn and :debug
24
20
  #
@@ -1,5 +1,6 @@
1
1
  require 'hiera/util'
2
- require 'hiera/recursive_lookup'
2
+ require 'hiera/recursive_guard'
3
+ require 'hiera/interpolate'
3
4
 
4
5
  begin
5
6
  require 'deep_merge'
@@ -8,21 +9,25 @@ end
8
9
 
9
10
  class Hiera
10
11
  module Backend
11
- INTERPOLATION = /%\{([^\}]*)\}/
12
-
13
12
  class << self
14
13
  # Data lives in /var/lib/hiera by default. If a backend
15
14
  # supplies a datadir in the config it will be used and
16
15
  # subject to variable expansion based on scope
17
16
  def datadir(backend, scope)
18
17
  backend = backend.to_sym
19
- default = Hiera::Util.var_dir
20
18
 
21
- if Config.include?(backend)
22
- parse_string(Config[backend][:datadir] || default, scope)
19
+ if Config[backend] && Config[backend][:datadir]
20
+ dir = Config[backend][:datadir]
23
21
  else
24
- parse_string(default, scope)
22
+ dir = Hiera::Util.var_dir
23
+ end
24
+
25
+ if !dir.is_a?(String)
26
+ raise(Hiera::InvalidConfigurationError,
27
+ "datadir for #{backend} cannot be an array")
25
28
  end
29
+
30
+ parse_string(dir, scope)
26
31
  end
27
32
 
28
33
  # Finds the path to a datafile based on the Backend#datadir
@@ -85,22 +90,8 @@ class Hiera
85
90
  #
86
91
  # @api public
87
92
  def parse_string(data, scope, extra_data={})
88
- interpolate(data, Hiera::RecursiveLookup.new(scope, extra_data))
89
- end
90
-
91
- def interpolate(data, values)
92
- if data.is_a?(String)
93
- data.gsub(INTERPOLATION) do
94
- name = $1
95
- values.lookup(name) do |value|
96
- interpolate(value, values)
97
- end
98
- end
99
- else
100
- data
101
- end
93
+ Hiera::Interpolate.interpolate(data, Hiera::RecursiveGuard.new, scope, extra_data)
102
94
  end
103
- private :interpolate
104
95
 
105
96
  # Parses a answer received from data files
106
97
  #
@@ -114,7 +105,8 @@ class Hiera
114
105
  elsif data.is_a?(Hash)
115
106
  answer = {}
116
107
  data.each_pair do |key, val|
117
- answer[key] = parse_answer(val, scope, extra_data)
108
+ interpolated_key = parse_string(key, scope, extra_data)
109
+ answer[interpolated_key] = parse_answer(val, scope, extra_data)
118
110
  end
119
111
 
120
112
  return answer
@@ -145,7 +137,7 @@ class Hiera
145
137
  # Deep merge options use the Hash utility function provided by [deep_merge](https://github.com/peritor/deep_merge)
146
138
  #
147
139
  # :native => Native Hash.merge
148
- # :deep => Use Hash.deep_merge
140
+ # :deep => Use Hash.deep_merge
149
141
  # :deeper => Use Hash.deep_merge!
150
142
  #
151
143
  def merge_answer(left,right)
@@ -205,6 +197,10 @@ class Hiera
205
197
  return default if answer.nil?
206
198
  return answer
207
199
  end
200
+
201
+ def clear!
202
+ @backends = {}
203
+ end
208
204
  end
209
205
  end
210
206
  end
@@ -21,7 +21,7 @@ class Hiera
21
21
 
22
22
  next unless File.exist?(jsonfile)
23
23
 
24
- data = @cache.read(jsonfile, Hash, {}) do |data|
24
+ data = @cache.read_file(jsonfile, Hash) do |data|
25
25
  JSON.parse(data)
26
26
  end
27
27
 
@@ -19,7 +19,7 @@ class Hiera
19
19
 
20
20
  next unless File.exist?(yamlfile)
21
21
 
22
- data = @cache.read(yamlfile, Hash, {}) do |data|
22
+ data = @cache.read_file(yamlfile, Hash) do |data|
23
23
  YAML.load(data)
24
24
  end
25
25
 
@@ -0,0 +1,4 @@
1
+ class Hiera
2
+ class Error < StandardError; end
3
+ class InvalidConfigurationError < Error; end
4
+ end
@@ -24,32 +24,44 @@ class Hiera
24
24
  # reading/parsing fails it will return {} instead
25
25
  #
26
26
  # Prior to calling this method you should be sure the file exist
27
- def read(path, expected_type=nil, default=nil)
28
- @cache[path] ||= {:data => nil, :meta => path_metadata(path)}
29
-
30
- if File.exist?(path) && !@cache[path][:data] || stale?(path)
31
- if block_given?
32
- begin
33
- @cache[path][:data] = yield(File.read(path))
34
- rescue => e
35
- Hiera.debug("Reading data from %s failed: %s: %S" % [path, e.class, e.to_s])
36
- @cache[path][:data] = default
37
- end
38
- else
39
- @cache[path][:data] = File.read(path)
40
- end
27
+ def read(path, expected_type = Object, default=nil, &block)
28
+ read_file(path, expected_type, &block)
29
+ rescue TypeError => detail
30
+ Hiera.debug("#{detail.message}, setting defaults")
31
+ @cache[path][:data] = default
32
+ rescue => detail
33
+ error = "Reading data from #{path} failed: #{detail.class}: #{detail}"
34
+ if default.nil?
35
+ raise detail
36
+ else
37
+ Hiera.debug(error)
38
+ @cache[path][:data] = default
41
39
  end
40
+ end
42
41
 
43
- if block_given? && !expected_type.nil?
44
- unless @cache[path][:data].is_a?(expected_type)
45
- Hiera.debug("Data retrieved from %s is not a %s, setting defaults" % [path, expected_type])
46
- @cache[path][:data] = default
42
+ # Read a file when it changes. If a file is re-read and has not changed since the last time
43
+ # then the last, processed, contents will be returned.
44
+ #
45
+ # The processed data can also be checked against an expected type. If the
46
+ # type does not match a TypeError is raised.
47
+ #
48
+ # No error handling is done inside this method. Any failed reads or errors
49
+ # in processing will be propagated to the caller
50
+ def read_file(path, expected_type = Object)
51
+ if stale?(path)
52
+ data = File.read(path)
53
+ @cache[path][:data] = block_given? ? yield(data) : data
54
+
55
+ if !@cache[path][:data].is_a?(expected_type)
56
+ raise TypeError, "Data retrieved from #{path} is #{data.class} not #{expected_type}"
47
57
  end
48
58
  end
49
59
 
50
60
  @cache[path][:data]
51
61
  end
52
62
 
63
+ private
64
+
53
65
  def stale?(path)
54
66
  meta = path_metadata(path)
55
67
 
@@ -0,0 +1,48 @@
1
+ require 'hiera/backend'
2
+
3
+ class Hiera::Interpolate
4
+ class << self
5
+ INTERPOLATION = /%\{([^\}]*)\}/
6
+ METHOD_INTERPOLATION = /%\{(scope|hiera)\(['"]([^"']*)["']\)\}/
7
+
8
+ def interpolate(data, recurse_guard, scope, extra_data)
9
+ if data.is_a?(String) && (match = data.match(INTERPOLATION))
10
+ interpolation_variable = match[1]
11
+ recurse_guard.check(interpolation_variable) do
12
+ interpolate_method, key = get_interpolation_method_and_key(data)
13
+ interpolated_data = send(interpolate_method, data, key, scope, extra_data)
14
+ interpolate(interpolated_data, recurse_guard, scope, extra_data)
15
+ end
16
+ else
17
+ data
18
+ end
19
+ end
20
+
21
+ def get_interpolation_method_and_key(data)
22
+ if (match = data.match(METHOD_INTERPOLATION))
23
+ case match[1]
24
+ when 'hiera' then [:hiera_interpolate, match[2]]
25
+ when 'scope' then [:scope_interpolate, match[2]]
26
+ end
27
+ elsif (match = data.match(INTERPOLATION))
28
+ [:scope_interpolate, match[1]]
29
+ end
30
+ end
31
+ private :get_interpolation_method_and_key
32
+
33
+ def scope_interpolate(data, key, scope, extra_data)
34
+ value = scope[key]
35
+ if value.nil? || value == :undefined
36
+ value = extra_data[key]
37
+ end
38
+ data.sub(INTERPOLATION, value.to_s)
39
+ end
40
+ private :scope_interpolate
41
+
42
+ def hiera_interpolate(data, key, scope, extra_data)
43
+ value = Hiera::Backend.lookup(key, nil, scope, nil, :priority)
44
+ data.sub(METHOD_INTERPOLATION, value)
45
+ end
46
+ private :hiera_interpolate
47
+ end
48
+ end
@@ -0,0 +1,20 @@
1
+ # Allow for safe recursive lookup of values during variable interpolation.
2
+ #
3
+ # @api private
4
+ class Hiera::InterpolationLoop < StandardError; end
5
+
6
+ class Hiera::RecursiveGuard
7
+ def initialize
8
+ @seen = []
9
+ end
10
+
11
+ def check(value, &block)
12
+ if @seen.include?(value)
13
+ raise Hiera::InterpolationLoop, "Detected in [#{@seen.join(', ')}]"
14
+ end
15
+ @seen.push(value)
16
+ ret = yield
17
+ @seen.pop
18
+ ret
19
+ end
20
+ end
@@ -0,0 +1,89 @@
1
+ # The version method and constant are isolated in hiera/version.rb so that a
2
+ # simple `require 'hiera/version'` allows a rubygems gemspec or bundler
3
+ # Gemfile to get the hiera version of the gem install.
4
+ #
5
+ # The version is programatically settable because we want to allow the
6
+ # Raketasks and such to set the version based on the output of `git describe`
7
+
8
+
9
+ class Hiera
10
+ VERSION = "1.3.0-rc2"
11
+
12
+ ##
13
+ # version is a public API method intended to always provide a fast and
14
+ # lightweight way to determine the version of hiera.
15
+ #
16
+ # The intent is that software external to hiera be able to determine the
17
+ # hiera version with no side-effects. The expected use is:
18
+ #
19
+ # require 'hiera/version'
20
+ # version = Hiera.version
21
+ #
22
+ # This function has the following ordering precedence. This precedence list
23
+ # is designed to facilitate automated packaging tasks by simply writing to
24
+ # the VERSION file in the same directory as this source file.
25
+ #
26
+ # 1. If a version has been explicitly assigned using the Hiera.version=
27
+ # method, return that version.
28
+ # 2. If there is a VERSION file, read the contents, trim any
29
+ # trailing whitespace, and return that version string.
30
+ # 3. Return the value of the Hiera::VERSION constant hard-coded into
31
+ # the source code.
32
+ #
33
+ # If there is no VERSION file, the method must return the version string of
34
+ # the nearest parent version that is an officially released version. That is
35
+ # to say, if a branch named 3.1.x contains 25 patches on top of the most
36
+ # recent official release of 3.1.1, then the version method must return the
37
+ # string "3.1.1" if no "VERSION" file is present.
38
+ #
39
+ # By design the version identifier is _not_ intended to vary during the life
40
+ # a process. There is no guarantee provided that writing to the VERSION file
41
+ # while a Hiera process is running will cause the version string to be
42
+ # updated. On the contrary, the contents of the VERSION are cached to reduce
43
+ # filesystem accesses.
44
+ #
45
+ # The VERSION file is intended to be used by package maintainers who may be
46
+ # applying patches or otherwise changing the software version in a manner
47
+ # that warrants a different software version identifier. The VERSION file is
48
+ # intended to be managed and owned by the release process and packaging
49
+ # related tasks, and as such should not reside in version control. The
50
+ # VERSION constant is intended to be version controlled in history.
51
+ #
52
+ # Ideally, this behavior will allow package maintainers to precisely specify
53
+ # the version of the software they're packaging as in the following example:
54
+ #
55
+ # $ git describe --match "1.2.*" > lib/hiera/VERSION
56
+ # $ ruby -r hiera/version -e 'puts Hiera.version'
57
+ # 1.2.1-9-g9fda440
58
+ #
59
+ # @api public
60
+ #
61
+ # @return [String] containing the hiera version, e.g. "1.2.1"
62
+ def self.version
63
+ version_file = File.join(File.dirname(__FILE__), 'VERSION')
64
+ return @hiera_version if @hiera_version
65
+ if version = read_version_file(version_file)
66
+ @hiera_version = version
67
+ end
68
+ @hiera_version ||= VERSION
69
+ end
70
+
71
+ def self.version=(version)
72
+ @hiera_version = version
73
+ end
74
+
75
+ ##
76
+ # read_version_file reads the content of the "VERSION" file that lives in the
77
+ # same directory as this source code file.
78
+ #
79
+ # @api private
80
+ #
81
+ # @return [String] for example: "1.6.14-6-gea42046" or nil if the VERSION
82
+ # file does not exist.
83
+ def self.read_version_file(path)
84
+ if File.exists?(path)
85
+ File.read(path).chomp
86
+ end
87
+ end
88
+ private_class_method :read_version_file
89
+ end
@@ -33,7 +33,7 @@ class Hiera
33
33
  Backend.expects(:datafile).with(:json, {}, "one", "json").returns("/nonexisting/one.json").times(3)
34
34
  File.stubs(:exist?).with("/nonexisting/one.json").returns(true)
35
35
 
36
- @cache.expects(:read).with("/nonexisting/one.json", Hash, {}).returns({"stringval" => "string", "boolval" => true, "numericval" => 1}).times(3)
36
+ @cache.expects(:read_file).with("/nonexisting/one.json", Hash).returns({"stringval" => "string", "boolval" => true, "numericval" => 1}).times(3)
37
37
 
38
38
  @backend.lookup("stringval", {}, nil, :priority).should == "string"
39
39
  @backend.lookup("boolval", {}, nil, :priority).should == true
@@ -47,7 +47,7 @@ class Hiera
47
47
  Backend.expects(:datafile).with(:json, scope, "two", "json").never
48
48
 
49
49
  File.stubs(:exist?).with("/nonexisting/one.json").returns(true)
50
- @cache.expects(:read).with("/nonexisting/one.json", Hash, {}).returns({"key" => "test_%{rspec}"})
50
+ @cache.expects(:read_file).with("/nonexisting/one.json", Hash).returns({"key" => "test_%{rspec}"})
51
51
 
52
52
  @backend.lookup("key", scope, nil, :priority).should == "test_test"
53
53
  end
@@ -63,8 +63,8 @@ class Hiera
63
63
  File.expects(:exist?).with("/nonexisting/one.json").returns(true)
64
64
  File.expects(:exist?).with("/nonexisting/two.json").returns(true)
65
65
 
66
- @cache.expects(:read).with("/nonexisting/one.json", Hash, {}).returns({"key" => "answer"})
67
- @cache.expects(:read).with("/nonexisting/two.json", Hash, {}).returns({"key" => "answer"})
66
+ @cache.expects(:read_file).with("/nonexisting/one.json", Hash).returns({"key" => "answer"})
67
+ @cache.expects(:read_file).with("/nonexisting/two.json", Hash).returns({"key" => "answer"})
68
68
 
69
69
  @backend.lookup("key", {}, nil, :array).should == ["answer", "answer"]
70
70
  end
@@ -75,7 +75,7 @@ class Hiera
75
75
  Backend.expects(:datafile).with(:json, {"rspec" => "test"}, "one", "json").returns("/nonexisting/one.json")
76
76
 
77
77
  File.expects(:exist?).with("/nonexisting/one.json").returns(true)
78
- @cache.expects(:read).with("/nonexisting/one.json", Hash, {}).returns({"key" => "test_%{rspec}"})
78
+ @cache.expects(:read_file).with("/nonexisting/one.json", Hash).returns({"key" => "test_%{rspec}"})
79
79
 
80
80
  @backend.lookup("key", {"rspec" => "test"}, nil, :priority).should == "test_test"
81
81
  end
@@ -32,7 +32,7 @@ class Hiera
32
32
  Backend.expects(:datasources).multiple_yields(["one"], ["two"])
33
33
  Backend.expects(:datafile).with(:yaml, {}, "one", "yaml").returns("/nonexisting/one.yaml")
34
34
  Backend.expects(:datafile).with(:yaml, {}, "two", "yaml").returns(nil).never
35
- @cache.expects(:read).with("/nonexisting/one.yaml", Hash, {}).returns({"key"=>"answer"})
35
+ @cache.expects(:read_file).with("/nonexisting/one.yaml", Hash).returns({"key"=>"answer"})
36
36
  File.stubs(:exist?).with("/nonexisting/one.yaml").returns(true)
37
37
 
38
38
  @backend.lookup("key", {}, nil, :priority).should == "answer"
@@ -50,7 +50,7 @@ class Hiera
50
50
  Backend.expects(:datasources).multiple_yields(["one"])
51
51
  Backend.expects(:datafile).with(:yaml, {}, "one", "yaml").returns("/nonexisting/one.yaml")
52
52
  File.stubs(:exist?).with("/nonexisting/one.yaml").returns(true)
53
- @cache.expects(:read).with("/nonexisting/one.yaml", Hash, {}).returns({})
53
+ @cache.expects(:read_file).with("/nonexisting/one.yaml", Hash).returns({})
54
54
 
55
55
  @backend.lookup("key", {}, nil, :priority).should be_nil
56
56
  end
@@ -62,8 +62,8 @@ class Hiera
62
62
  File.stubs(:exist?).with("/nonexisting/one.yaml").returns(true)
63
63
  File.stubs(:exist?).with("/nonexisting/two.yaml").returns(true)
64
64
 
65
- @cache.expects(:read).with("/nonexisting/one.yaml", Hash, {}).returns({"key"=>"answer"})
66
- @cache.expects(:read).with("/nonexisting/two.yaml", Hash, {}).returns({"key"=>"answer"})
65
+ @cache.expects(:read_file).with("/nonexisting/one.yaml", Hash).returns({"key"=>"answer"})
66
+ @cache.expects(:read_file).with("/nonexisting/two.yaml", Hash).returns({"key"=>"answer"})
67
67
 
68
68
  @backend.lookup("key", {}, nil, :array).should == ["answer", "answer"]
69
69
  end
@@ -75,8 +75,8 @@ class Hiera
75
75
  File.stubs(:exist?).with("/nonexisting/one.yaml").returns(true)
76
76
  File.stubs(:exist?).with("/nonexisting/two.yaml").returns(true)
77
77
 
78
- @cache.expects(:read).with("/nonexisting/one.yaml", Hash, {}).returns({})
79
- @cache.expects(:read).with("/nonexisting/two.yaml", Hash, {}).returns({"key"=>{"a"=>"answer"}})
78
+ @cache.expects(:read_file).with("/nonexisting/one.yaml", Hash).returns({})
79
+ @cache.expects(:read_file).with("/nonexisting/two.yaml", Hash).returns({"key"=>{"a"=>"answer"}})
80
80
 
81
81
  @backend.lookup("key", {}, nil, :hash).should == {"a" => "answer"}
82
82
  end
@@ -88,8 +88,8 @@ class Hiera
88
88
  File.stubs(:exist?).with("/nonexisting/one.yaml").returns(true)
89
89
  File.stubs(:exist?).with("/nonexisting/two.yaml").returns(true)
90
90
 
91
- @cache.expects(:read).with("/nonexisting/one.yaml", Hash, {}).returns({"key"=>{"a"=>"answer"}})
92
- @cache.expects(:read).with("/nonexisting/two.yaml", Hash, {}).returns({"key"=>{"b"=>"answer", "a"=>"wrong"}})
91
+ @cache.expects(:read_file).with("/nonexisting/one.yaml", Hash).returns({"key"=>{"a"=>"answer"}})
92
+ @cache.expects(:read_file).with("/nonexisting/two.yaml", Hash).returns({"key"=>{"b"=>"answer", "a"=>"wrong"}})
93
93
 
94
94
  @backend.lookup("key", {}, nil, :hash).should == {"a" => "answer", "b" => "answer"}
95
95
  end
@@ -101,8 +101,8 @@ class Hiera
101
101
  File.stubs(:exist?).with("/nonexisting/one.yaml").returns(true)
102
102
  File.stubs(:exist?).with("/nonexisting/two.yaml").returns(true)
103
103
 
104
- @cache.expects(:read).with("/nonexisting/one.yaml", Hash, {}).returns({"key"=>["a", "answer"]})
105
- @cache.expects(:read).with("/nonexisting/two.yaml", Hash, {}).returns({"key"=>{"a"=>"answer"}})
104
+ @cache.expects(:read_file).with("/nonexisting/one.yaml", Hash).returns({"key"=>["a", "answer"]})
105
+ @cache.expects(:read_file).with("/nonexisting/two.yaml", Hash).returns({"key"=>{"a"=>"answer"}})
106
106
 
107
107
  expect {@backend.lookup("key", {}, nil, :array)}.to raise_error(Exception, "Hiera type mismatch: expected Array and got Hash")
108
108
  end
@@ -114,8 +114,8 @@ class Hiera
114
114
  File.stubs(:exist?).with("/nonexisting/one.yaml").returns(true)
115
115
  File.stubs(:exist?).with("/nonexisting/two.yaml").returns(true)
116
116
 
117
- @cache.expects(:read).with("/nonexisting/one.yaml", Hash, {}).returns({"key"=>{"a"=>"answer"}})
118
- @cache.expects(:read).with("/nonexisting/two.yaml", Hash, {}).returns({"key"=>["a", "wrong"]})
117
+ @cache.expects(:read_file).with("/nonexisting/one.yaml", Hash).returns({"key"=>{"a"=>"answer"}})
118
+ @cache.expects(:read_file).with("/nonexisting/two.yaml", Hash).returns({"key"=>["a", "wrong"]})
119
119
 
120
120
  expect { @backend.lookup("key", {}, nil, :hash) }.to raise_error(Exception, "Hiera type mismatch: expected Hash and got Array")
121
121
  end
@@ -125,7 +125,7 @@ class Hiera
125
125
  Backend.expects(:datafile).with(:yaml, {"rspec" => "test"}, "one", "yaml").returns("/nonexisting/one.yaml")
126
126
  File.stubs(:exist?).with("/nonexisting/one.yaml").returns(true)
127
127
 
128
- @cache.expects(:read).with("/nonexisting/one.yaml", Hash, {}).returns({"key"=>"test_%{rspec}"})
128
+ @cache.expects(:read_file).with("/nonexisting/one.yaml", Hash).returns({"key"=>"test_%{rspec}"})
129
129
 
130
130
  @backend.lookup("key", {"rspec" => "test"}, nil, :priority).should == "test_test"
131
131
  end
@@ -137,7 +137,7 @@ class Hiera
137
137
 
138
138
  yaml = "---\nstringval: 'string'\nboolval: true\nnumericval: 1"
139
139
 
140
- @cache.expects(:read).with("/nonexisting/one.yaml", Hash, {}).times(3).returns({"boolval"=>true, "numericval"=>1, "stringval"=>"string"})
140
+ @cache.expects(:read_file).with("/nonexisting/one.yaml", Hash).times(3).returns({"boolval"=>true, "numericval"=>1, "stringval"=>"string"})
141
141
 
142
142
  @backend.lookup("stringval", {}, nil, :priority).should == "string"
143
143
  @backend.lookup("boolval", {}, nil, :priority).should == true
@@ -5,15 +5,30 @@ class Hiera
5
5
  describe Backend do
6
6
  describe "#datadir" do
7
7
  it "interpolates any values in the configured value" do
8
- Config.load({:rspec => {:datadir => "/tmp"}})
9
- Backend.expects(:parse_string).with("/tmp", {})
10
- Backend.datadir(:rspec, {})
8
+ Config.load({:rspec => {:datadir => "/tmp/%{interpolate}"}})
9
+
10
+ dir = Backend.datadir(:rspec, { "interpolate" => "my_data" })
11
+
12
+ dir.should == "/tmp/my_data"
11
13
  end
12
14
 
13
15
  it "defaults to a directory in var" do
14
16
  Config.load({})
15
- Backend.expects(:parse_string).with(Hiera::Util.var_dir, {})
16
- Backend.datadir(:rspec, {})
17
+ Backend.datadir(:rspec, {}).should == Hiera::Util.var_dir
18
+
19
+ Config.load({:rspec => nil})
20
+ Backend.datadir(:rspec, {}).should == Hiera::Util.var_dir
21
+
22
+ Config.load({:rspec => {}})
23
+ Backend.datadir(:rspec, {}).should == Hiera::Util.var_dir
24
+ end
25
+
26
+ it "fails when the datadir is an array" do
27
+ Config.load({:rspec => {:datadir => []}})
28
+
29
+ expect do
30
+ Backend.datadir(:rspec, {})
31
+ end.to raise_error(Hiera::InvalidConfigurationError, /datadir for rspec cannot be an array/)
17
32
  end
18
33
  end
19
34
 
@@ -103,11 +118,19 @@ class Hiera
103
118
  Backend.parse_string(input, {}).should == input
104
119
  end
105
120
 
106
- it "replaces interpolations with data looked up in the scope" do
107
- input = "replace %{part1} and %{part2}"
108
- scope = {"part1" => "value of part1", "part2" => "value of part2"}
121
+ @scope_interpolation_tests = {
122
+ "replace %{part1} and %{part2}" =>
123
+ "replace value of part1 and value of part2",
124
+ "replace %{scope('part1')} and %{scope('part2')}" =>
125
+ "replace value of part1 and value of part2"
126
+ }
127
+
128
+ @scope_interpolation_tests.each do |input, expected|
129
+ it "replaces interpolations with data looked up in the scope" do
130
+ scope = {"part1" => "value of part1", "part2" => "value of part2"}
109
131
 
110
- Backend.parse_string(input, scope).should == "replace value of part1 and value of part2"
132
+ Backend.parse_string(input, scope).should == expected
133
+ end
111
134
  end
112
135
 
113
136
  it "replaces interpolations with data looked up in extra_data when scope does not contain the value" do
@@ -120,14 +143,27 @@ class Hiera
120
143
  Backend.parse_string(input, {"rspec" => "test"}, {"rspec" => "fail"}).should == "test_test_test"
121
144
  end
122
145
 
123
- it "interprets nil in scope as a non-value" do
124
- input = "test_%{rspec}_test"
125
- Backend.parse_string(input, {"rspec" => nil}).should == "test__test"
146
+ @interprets_nil_in_scope_tests = {
147
+ "test_%{rspec}_test" => "test__test",
148
+ "test_%{scope('rspec')}_test" => "test__test"
149
+ }
150
+
151
+ @interprets_nil_in_scope_tests.each do |input, expected|
152
+ it "interprets nil in scope as a non-value" do
153
+ Backend.parse_string(input, {"rspec" => nil}).should == expected
154
+ end
126
155
  end
127
156
 
128
- it "interprets false in scope as a real value" do
129
- input = "test_%{rspec}_test"
130
- Backend.parse_string(input, {"rspec" => false}).should == "test_false_test"
157
+ @interprets_false_in_scope_tests = {
158
+ "test_%{rspec}_test" => "test_false_test",
159
+ "test_%{scope('rspec')}_test" => "test_false_test"
160
+ }
161
+
162
+ @interprets_false_in_scope_tests.each do |input, expected|
163
+ it "interprets false in scope as a real value" do
164
+ input = "test_%{scope('rspec')}_test"
165
+ Backend.parse_string(input, {"rspec" => false}).should == expected
166
+ end
131
167
  end
132
168
 
133
169
  it "interprets false in extra_data as a real value" do
@@ -140,9 +176,15 @@ class Hiera
140
176
  Backend.parse_string(input, {}, {"rspec" => nil}).should == "test__test"
141
177
  end
142
178
 
143
- it "interprets :undefined in scope as a non-value" do
144
- input = "test_%{rspec}_test"
145
- Backend.parse_string(input, {"rspec" => :undefined}).should == "test__test"
179
+ @interprets_undefined_in_scope_tests = {
180
+ "test_%{rspec}_test" => "test__test",
181
+ "test_%{scope('rspec')}_test" => "test__test"
182
+ }
183
+
184
+ @interprets_undefined_in_scope_tests.each do |input, expected|
185
+ it "interprets :undefined in scope as a non-value" do
186
+ Backend.parse_string(input, {"rspec" => :undefined}).should == expected
187
+ end
146
188
  end
147
189
 
148
190
  it "uses the value from extra_data when scope is :undefined" do
@@ -150,24 +192,51 @@ class Hiera
150
192
  Backend.parse_string(input, {"rspec" => :undefined}, { "rspec" => "extra" }).should == "test_extra_test"
151
193
  end
152
194
 
153
- it "looks up the interpolated value exactly as it appears in the input" do
154
- input = "test_%{::rspec::data}_test"
155
- Backend.parse_string(input, {"::rspec::data" => "value"}).should == "test_value_test"
195
+ @exact_lookup_tests = {
196
+ "test_%{::rspec::data}_test" => "test_value_test",
197
+ "test_%{scope('::rspec::data')}_test" => "test_value_test"
198
+ }
199
+
200
+ @exact_lookup_tests.each do |input, expected|
201
+ it "looks up the interpolated value exactly as it appears in the input" do
202
+ Backend.parse_string(input, {"::rspec::data" => "value"}).should == expected
203
+ end
156
204
  end
157
205
 
158
- it "does not remove any surrounding whitespace when parsing the key to lookup" do
159
- input = "test_%{\trspec::data }_test"
160
- Backend.parse_string(input, {"\trspec::data " => "value"}).should == "test_value_test"
206
+ @surrounding_whitespace_tests = {
207
+ "test_%{\trspec::data }_test" => "test_value_test",
208
+ "test_%{scope('\trspec::data ')}_test" => "test_value_test"
209
+ }
210
+ @surrounding_whitespace_tests.each do |input, expected|
211
+ it "does not remove any surrounding whitespace when parsing the key to lookup" do
212
+ Backend.parse_string(input, {"\trspec::data " => "value"}).should == expected
213
+ end
161
214
  end
162
215
 
163
- it "does not try removing leading :: when a full lookup fails (#17434)" do
164
- input = "test_%{::rspec::data}_test"
165
- Backend.parse_string(input, {"rspec::data" => "value"}).should == "test__test"
216
+ @leading_double_colon_tests = {
217
+ "test_%{::rspec::data}_test" => "test__test",
218
+ "test_%{scope('::rspec::data')}_test" => "test__test"
219
+ }
220
+
221
+ @leading_double_colon_tests.each do |input, expected|
222
+ it "does not try removing leading :: when a full lookup fails (#17434)" do
223
+ Backend.parse_string(input, {"rspec::data" => "value"}).should == expected
224
+ end
225
+ end
226
+
227
+ @double_colon_key_tests = {
228
+ "test_%{::rspec::data}_test" => "test__test",
229
+ "test_%{scope('::rspec::data')}_test" => "test__test"
230
+ }
231
+ @double_colon_key_tests.each do |input, expected|
232
+ it "does not try removing leading sections separated by :: when a full lookup fails (#17434)" do
233
+ Backend.parse_string(input, {"data" => "value"}).should == expected
234
+ end
166
235
  end
167
236
 
168
- it "does not try removing leading sections separated by :: when a full lookup fails (#17434)" do
169
- input = "test_%{::rspec::data}_test"
170
- Backend.parse_string(input, {"data" => "value"}).should == "test__test"
237
+ it "does not try removing unknown, preceeding characters when looking up values" do
238
+ input = "test_%{$var}_test"
239
+ Backend.parse_string(input, {"$var" => "value"}).should == "test_value_test"
171
240
  end
172
241
 
173
242
  it "looks up recursively" do
@@ -181,7 +250,17 @@ class Hiera
181
250
  input = "test_%{first}_test"
182
251
  expect do
183
252
  Backend.parse_string(input, scope)
184
- end.to raise_error Exception, "Interpolation loop detected in [first, second]"
253
+ end.to raise_error Hiera::InterpolationLoop, "Detected in [first, second]"
254
+ end
255
+
256
+ it "replaces hiera interpolations with data looked up in hiera" do
257
+ input = "%{hiera('key1')}"
258
+ scope = {}
259
+ Config.load({:yaml => {:datadir => "/tmp"}})
260
+ Config.load_backends
261
+ Backend::Yaml_backend.any_instance.stubs(:lookup).with("key1", scope, nil, :priority).returns("answer")
262
+
263
+ Backend.parse_string(input, scope).should == "answer"
185
264
  end
186
265
  end
187
266
 
@@ -201,11 +280,93 @@ class Hiera
201
280
  Backend.parse_answer(input, {"rspec" => "test"}).should == {"foo"=>"test_test_test", "bar"=>"test_test_test"}
202
281
  end
203
282
 
283
+ it "interpolates string in hash keys" do
284
+ input = {"%{rspec}" => "test"}
285
+ Backend.parse_answer(input, {"rspec" => "foo"}).should == {"foo"=>"test"}
286
+ end
287
+
288
+ it "interpolates strings in nested hash keys" do
289
+ input = {"topkey" => {"%{rspec}" => "test"}}
290
+ Backend.parse_answer(input, {"rspec" => "foo"}).should == {"topkey"=>{"foo" => "test"}}
291
+ end
292
+
204
293
  it "interpolates strings in a mixed structure of arrays and hashes" do
205
294
  input = {"foo" => "test_%{rspec}_test", "bar" => ["test_%{rspec}_test", "test_%{rspec}_test"]}
206
295
  Backend.parse_answer(input, {"rspec" => "test"}).should == {"foo"=>"test_test_test", "bar"=>["test_test_test", "test_test_test"]}
207
296
  end
208
297
 
298
+ it "interpolates hiera lookups values in strings" do
299
+ input = "test_%{hiera('rspec')}_test"
300
+ scope = {}
301
+ Config.load({:yaml => {:datadir => "/tmp"}})
302
+ Config.load_backends
303
+ Backend::Yaml_backend.any_instance.stubs(:lookup).with("rspec", scope, nil, :priority).returns("test")
304
+ Backend.parse_answer(input, scope).should == "test_test_test"
305
+ end
306
+
307
+ it "interpolates hiera lookups in each string in an array" do
308
+ input = ["test_%{hiera('rspec')}_test", "test_%{hiera('rspec')}_test", ["test_%{hiera('rspec')}_test"]]
309
+ scope = {}
310
+ Config.load({:yaml => {:datadir => "/tmp"}})
311
+ Config.load_backends
312
+ Backend::Yaml_backend.any_instance.stubs(:lookup).with("rspec", scope, nil, :priority).returns("test")
313
+ Backend.parse_answer(input, scope).should == ["test_test_test", "test_test_test", ["test_test_test"]]
314
+ end
315
+
316
+ it "interpolates hiera lookups in each string in a hash" do
317
+ input = {"foo" => "test_%{hiera('rspec')}_test", "bar" => "test_%{hiera('rspec')}_test"}
318
+ scope = {}
319
+ Config.load({:yaml => {:datadir => "/tmp"}})
320
+ Config.load_backends
321
+ Backend::Yaml_backend.any_instance.stubs(:lookup).with("rspec", scope, nil, :priority).returns("test")
322
+ Backend.parse_answer(input, scope).should == {"foo"=>"test_test_test", "bar"=>"test_test_test"}
323
+ end
324
+
325
+ it "interpolates hiera lookups in string in hash keys" do
326
+ input = {"%{hiera('rspec')}" => "test"}
327
+ scope = {}
328
+ Config.load({:yaml => {:datadir => "/tmp"}})
329
+ Config.load_backends
330
+ Backend::Yaml_backend.any_instance.stubs(:lookup).with("rspec", scope, nil, :priority).returns("foo")
331
+ Backend.parse_answer(input, scope).should == {"foo"=>"test"}
332
+ end
333
+
334
+ it "interpolates hiera lookups in strings in nested hash keys" do
335
+ input = {"topkey" => {"%{hiera('rspec')}" => "test"}}
336
+ scope = {}
337
+ Config.load({:yaml => {:datadir => "/tmp"}})
338
+ Config.load_backends
339
+ Backend::Yaml_backend.any_instance.stubs(:lookup).with("rspec", scope, nil, :priority).returns("foo")
340
+ Backend.parse_answer(input, scope).should == {"topkey"=>{"foo" => "test"}}
341
+ end
342
+
343
+ it "interpolates hiera lookups in strings in a mixed structure of arrays and hashes" do
344
+ input = {"foo" => "test_%{hiera('rspec')}_test", "bar" => ["test_%{hiera('rspec')}_test", "test_%{hiera('rspec')}_test"]}
345
+ scope = {}
346
+ Config.load({:yaml => {:datadir => "/tmp"}})
347
+ Config.load_backends
348
+ Backend::Yaml_backend.any_instance.stubs(:lookup).with("rspec", scope, nil, :priority).returns("test")
349
+ Backend.parse_answer(input, scope).should == {"foo"=>"test_test_test", "bar"=>["test_test_test", "test_test_test"]}
350
+ end
351
+
352
+ it "interpolates hiera lookups and scope lookups in the same string" do
353
+ input = {"foo" => "test_%{hiera('rspec')}_test", "bar" => "test_%{rspec2}_test"}
354
+ scope = {"rspec2" => "scope_rspec"}
355
+ Config.load({:yaml => {:datadir => "/tmp"}})
356
+ Config.load_backends
357
+ Backend::Yaml_backend.any_instance.stubs(:lookup).with("rspec", scope, nil, :priority).returns("hiera_rspec")
358
+ Backend.parse_answer(input, scope).should == {"foo"=>"test_hiera_rspec_test", "bar"=>"test_scope_rspec_test"}
359
+ end
360
+
361
+ it "interpolates hiera and scope lookups with the same lookup query in a single string" do
362
+ input = "test_%{hiera('rspec')}_test_%{rspec}"
363
+ scope = {"rspec" => "scope_rspec"}
364
+ Config.load({:yaml => {:datadir => "/tmp"}})
365
+ Config.load_backends
366
+ Backend::Yaml_backend.any_instance.stubs(:lookup).with("rspec", scope, nil, :priority).returns("hiera_rspec")
367
+ Backend.parse_answer(input, scope).should == "test_hiera_rspec_test_scope_rspec"
368
+ end
369
+
209
370
  it "passes integers unchanged" do
210
371
  input = 1
211
372
  Backend.parse_answer(input, {"rspec" => "test"}).should == 1
@@ -225,6 +386,12 @@ class Hiera
225
386
  input = false
226
387
  Backend.parse_answer(input, {"rspec" => "test"}).should == false
227
388
  end
389
+
390
+ it "interpolates lookups using single or double quotes" do
391
+ input = "test_%{scope(\"rspec\")}_test_%{scope('rspec')}"
392
+ scope = {"rspec" => "scope_rspec"}
393
+ Backend.parse_answer(input, scope).should == "test_scope_rspec_test_scope_rspec"
394
+ end
228
395
  end
229
396
 
230
397
  describe "#resolve_answer" do
@@ -244,6 +411,7 @@ class Hiera
244
411
  end
245
412
 
246
413
  it "caches loaded backends" do
414
+ Backend.clear!
247
415
  Hiera.expects(:debug).with(regexp_matches(/Hiera YAML backend starting/)).once
248
416
 
249
417
  Config.load({:yaml => {:datadir => "/tmp"}})
@@ -1,62 +1,141 @@
1
1
  require 'spec_helper'
2
+ require 'tmpdir'
2
3
 
3
4
  class Hiera
4
5
  describe Filecache do
5
6
  before do
6
- File.stubs(:exist?).returns(true)
7
7
  @cache = Filecache.new
8
8
  end
9
9
 
10
+ def write_file(file, contents)
11
+ File.open(file, 'w') do |f|
12
+ f.write(contents)
13
+ end
14
+ end
15
+
10
16
  describe "#read" do
11
- it "should cache and read data" do
12
- File.expects(:read).with("/nonexisting").returns("text")
13
- @cache.expects(:path_metadata).returns(File.stat(__FILE__)).once
14
- @cache.expects(:stale?).once.returns(false)
17
+ it "reads data from a file" do
18
+ Dir.mktmpdir do |dir|
19
+ file = File.join(dir, "testing")
20
+ write_file(file, "my data")
21
+
22
+ @cache.read(file).should == "my data"
23
+ end
24
+ end
25
+
26
+ it "rereads data when the file changes" do
27
+ Dir.mktmpdir do |dir|
28
+ file = File.join(dir, "testing")
29
+ write_file(file, "my data")
30
+ @cache.read(file).should == "my data"
15
31
 
16
- @cache.read("/nonexisting").should == "text"
17
- @cache.read("/nonexisting").should == "text"
32
+ write_file(file, "changed data")
33
+ @cache.read(file).should == "changed data"
34
+ end
18
35
  end
19
36
 
20
- it "should support validating return types and setting defaults" do
21
- File.expects(:read).with("/nonexisting").returns('{"rspec":1}')
37
+ it "uses the provided default when the type does not match the expected type" do
38
+ Hiera.expects(:debug).with(regexp_matches(/String.*not.*Hash, setting defaults/))
39
+ Dir.mktmpdir do |dir|
40
+ file = File.join(dir, "testing")
41
+ write_file(file, "my data")
42
+ data = @cache.read(file, Hash, { :testing => "hash" }) do |data|
43
+ "a string"
44
+ end
22
45
 
23
- @cache.expects(:path_metadata).returns(File.stat(__FILE__))
46
+ data.should == { :testing => "hash" }
47
+ end
48
+ end
24
49
 
25
- Hiera.expects(:debug).with(regexp_matches(/is not a Hash, setting defaults/))
50
+ it "traps any errors from the block and uses the default value" do
51
+ Hiera.expects(:debug).with(regexp_matches(/Reading data.*failed:.*testing error/))
52
+ Dir.mktmpdir do |dir|
53
+ file = File.join(dir, "testing")
54
+ write_file(file, "my data")
55
+ data = @cache.read(file, Hash, { :testing => "hash" }) do |data|
56
+ raise ArgumentError, "testing error"
57
+ end
26
58
 
27
- # return bogus data on purpose, triggers setting defaults
28
- data = @cache.read("/nonexisting", Hash, {"rspec" => 1}) do |data|
29
- nil
59
+ data.should == { :testing => "hash" }
30
60
  end
61
+ end
31
62
 
32
- data.should == {"rspec" => 1}
63
+ it "raises an error when there is no default given and there is a problem" do
64
+ Dir.mktmpdir do |dir|
65
+ file = File.join(dir, "testing")
66
+ write_file(file, "my data")
67
+
68
+ expect do
69
+ @cache.read(file, Hash) do |data|
70
+ raise ArgumentError, "testing error"
71
+ end
72
+ end.to raise_error(ArgumentError, "testing error")
73
+ end
33
74
  end
34
75
  end
35
76
 
36
- describe "#stale?" do
37
- it "should return false when the file has not changed" do
38
- stat = File.stat(__FILE__)
77
+ describe "#read_file" do
78
+ it "reads data from a file" do
79
+ Dir.mktmpdir do |dir|
80
+ file = File.join(dir, "testing")
81
+ write_file(file, "my data")
39
82
 
40
- @cache.stubs(:path_metadata).returns(stat)
41
- @cache.stale?("/nonexisting").should == true
42
- @cache.stale?("/nonexisting").should == false
83
+ @cache.read_file(file).should == "my data"
84
+ end
43
85
  end
44
86
 
45
- it "should update and return true when the file changed" do
46
- @cache.expects(:path_metadata).returns({:inode => 1, :mtime => Time.now, :size => 1})
47
- @cache.stale?("/nonexisting").should == true
48
- @cache.expects(:path_metadata).returns({:inode => 2, :mtime => Time.now, :size => 1})
49
- @cache.stale?("/nonexisting").should == true
87
+ it "rereads data when the file changes" do
88
+ Dir.mktmpdir do |dir|
89
+ file = File.join(dir, "testing")
90
+ write_file(file, "my data")
91
+ @cache.read_file(file).should == "my data"
92
+
93
+ write_file(file, "changed data")
94
+ @cache.read_file(file).should == "changed data"
95
+ end
50
96
  end
51
- end
52
97
 
53
- describe "#path_metadata" do
54
- it "should return the right data" do
55
- stat = File.stat(__FILE__)
98
+ it "errors when the type does not match the expected type" do
99
+ Dir.mktmpdir do |dir|
100
+ file = File.join(dir, "testing")
101
+ write_file(file, "my data")
56
102
 
57
- File.expects(:stat).with("/nonexisting").returns(stat)
103
+ expect do
104
+ @cache.read_file(file, Hash) do |data|
105
+ "a string"
106
+ end
107
+ end.to raise_error(TypeError)
108
+ end
109
+ end
110
+
111
+ it "converts the read data using the block" do
112
+ Dir.mktmpdir do |dir|
113
+ file = File.join(dir, "testing")
114
+ write_file(file, "my data")
58
115
 
59
- @cache.path_metadata("/nonexisting").should == {:inode => stat.ino, :mtime => stat.mtime, :size => stat.size}
116
+ @cache.read_file(file, Hash) do |data|
117
+ { :data => data }
118
+ end.should == { :data => "my data" }
119
+ end
120
+ end
121
+
122
+ it "errors when the file does not exist" do
123
+ expect do
124
+ @cache.read_file("/notexist")
125
+ end.to raise_error(Errno::ENOENT)
126
+ end
127
+
128
+ it "propogates any errors from the block" do
129
+ Dir.mktmpdir do |dir|
130
+ file = File.join(dir, "testing")
131
+ write_file(file, "my data")
132
+
133
+ expect do
134
+ @cache.read_file(file) do |data|
135
+ raise ArgumentError, "testing error"
136
+ end
137
+ end.to raise_error(ArgumentError, "testing error")
138
+ end
60
139
  end
61
140
  end
62
141
  end
@@ -0,0 +1,44 @@
1
+ require "spec_helper"
2
+ require "hiera/version"
3
+ require 'pathname'
4
+
5
+ describe "Hiera.version Public API" do
6
+ subject() { Hiera }
7
+
8
+ before :each do
9
+ Hiera.instance_eval do
10
+ if @hiera_version
11
+ @hiera_version = nil
12
+ end
13
+ end
14
+ end
15
+
16
+ context "without a VERSION file" do
17
+ before :each do
18
+ subject.stubs(:read_version_file).returns(nil)
19
+ end
20
+
21
+ it "is Hiera::VERSION" do
22
+ subject.version.should == Hiera::VERSION
23
+ end
24
+ it "respects the version= setter" do
25
+ subject.version = '1.2.3'
26
+ subject.version.should == '1.2.3'
27
+ end
28
+ end
29
+
30
+ context "with a VERSION file" do
31
+ it "is the content of the file" do
32
+ subject.expects(:read_version_file).with() do |path|
33
+ pathname = Pathname.new(path)
34
+ pathname.basename.to_s == "VERSION"
35
+ end.returns('1.2.1-9-g9fda440')
36
+
37
+ subject.version.should == '1.2.1-9-g9fda440'
38
+ end
39
+ it "respects the version= setter" do
40
+ subject.version = '1.2.3'
41
+ subject.version.should == '1.2.3'
42
+ end
43
+ end
44
+ end
metadata CHANGED
@@ -1,114 +1,104 @@
1
- --- !ruby/object:Gem::Specification
1
+ --- !ruby/object:Gem::Specification
2
2
  name: hiera
3
- version: !ruby/object:Gem::Version
4
- hash: 29
5
- prerelease:
6
- segments:
7
- - 1
8
- - 2
9
- - 1
10
- version: 1.2.1
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.3.0.rc2
5
+ prerelease: 6
11
6
  platform: ruby
12
- authors:
7
+ authors:
13
8
  - Puppet Labs
14
9
  autorequire:
15
10
  bindir: bin
16
11
  cert_chain: []
17
-
18
- date: 2013-04-18 00:00:00 Z
19
- dependencies:
20
- - !ruby/object:Gem::Dependency
12
+ date: 2013-11-04 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
21
15
  name: json_pure
22
- prerelease: false
23
- requirement: &id001 !ruby/object:Gem::Requirement
16
+ requirement: !ruby/object:Gem::Requirement
24
17
  none: false
25
- requirements:
26
- - - ">="
27
- - !ruby/object:Gem::Version
28
- hash: 3
29
- segments:
30
- - 0
31
- version: "0"
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: '0'
32
22
  type: :runtime
33
- version_requirements: *id001
23
+ prerelease: false
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ! '>='
28
+ - !ruby/object:Gem::Version
29
+ version: '0'
34
30
  description: A pluggable data store for hierarcical data
35
31
  email: info@puppetlabs.com
36
- executables:
32
+ executables:
37
33
  - hiera
38
34
  extensions: []
39
-
40
35
  extra_rdoc_files: []
41
-
42
- files:
36
+ files:
43
37
  - bin/hiera
44
- - lib/hiera/puppet_logger.rb
45
- - lib/hiera/recursive_lookup.rb
38
+ - lib/hiera.rb
46
39
  - lib/hiera/console_logger.rb
47
- - lib/hiera/filecache.rb
48
- - lib/hiera/fallback_logger.rb
49
- - lib/hiera/util.rb
50
- - lib/hiera/backend.rb
51
40
  - lib/hiera/noop_logger.rb
52
- - lib/hiera/config.rb
53
41
  - lib/hiera/backend/yaml_backend.rb
54
42
  - lib/hiera/backend/json_backend.rb
55
- - lib/hiera.rb
43
+ - lib/hiera/fallback_logger.rb
44
+ - lib/hiera/filecache.rb
45
+ - lib/hiera/version.rb
46
+ - lib/hiera/config.rb
47
+ - lib/hiera/interpolate.rb
48
+ - lib/hiera/recursive_guard.rb
49
+ - lib/hiera/util.rb
50
+ - lib/hiera/backend.rb
51
+ - lib/hiera/puppet_logger.rb
52
+ - lib/hiera/error.rb
56
53
  - COPYING
57
54
  - README.md
58
55
  - LICENSE
59
- - spec/unit/util_spec.rb
60
- - spec/unit/puppet_logger_spec.rb
61
- - spec/unit/config_spec.rb
62
- - spec/unit/backend_spec.rb
63
- - spec/unit/filecache_spec.rb
64
56
  - spec/unit/hiera_spec.rb
65
- - spec/unit/console_logger_spec.rb
57
+ - spec/unit/filecache_spec.rb
66
58
  - spec/unit/backend/yaml_backend_spec.rb
67
59
  - spec/unit/backend/json_backend_spec.rb
60
+ - spec/unit/console_logger_spec.rb
61
+ - spec/unit/backend_spec.rb
62
+ - spec/unit/version_spec.rb
63
+ - spec/unit/puppet_logger_spec.rb
64
+ - spec/unit/config_spec.rb
68
65
  - spec/unit/fallback_logger_spec.rb
66
+ - spec/unit/util_spec.rb
69
67
  - spec/spec_helper.rb
70
68
  homepage: https://github.com/puppetlabs/hiera
71
69
  licenses: []
72
-
73
70
  post_install_message:
74
71
  rdoc_options: []
75
-
76
- require_paths:
72
+ require_paths:
77
73
  - lib
78
- required_ruby_version: !ruby/object:Gem::Requirement
74
+ required_ruby_version: !ruby/object:Gem::Requirement
79
75
  none: false
80
- requirements:
81
- - - ">="
82
- - !ruby/object:Gem::Version
83
- hash: 3
84
- segments:
85
- - 0
86
- version: "0"
87
- required_rubygems_version: !ruby/object:Gem::Requirement
76
+ requirements:
77
+ - - ! '>='
78
+ - !ruby/object:Gem::Version
79
+ version: '0'
80
+ required_rubygems_version: !ruby/object:Gem::Requirement
88
81
  none: false
89
- requirements:
90
- - - ">="
91
- - !ruby/object:Gem::Version
92
- hash: 3
93
- segments:
94
- - 0
95
- version: "0"
82
+ requirements:
83
+ - - ! '>'
84
+ - !ruby/object:Gem::Version
85
+ version: 1.3.1
96
86
  requirements: []
97
-
98
87
  rubyforge_project:
99
- rubygems_version: 1.8.24
88
+ rubygems_version: 1.8.23
100
89
  signing_key:
101
90
  specification_version: 3
102
91
  summary: Light weight hierarchical data store
103
- test_files:
104
- - spec/unit/util_spec.rb
105
- - spec/unit/puppet_logger_spec.rb
106
- - spec/unit/config_spec.rb
107
- - spec/unit/backend_spec.rb
108
- - spec/unit/filecache_spec.rb
92
+ test_files:
109
93
  - spec/unit/hiera_spec.rb
110
- - spec/unit/console_logger_spec.rb
94
+ - spec/unit/filecache_spec.rb
111
95
  - spec/unit/backend/yaml_backend_spec.rb
112
96
  - spec/unit/backend/json_backend_spec.rb
97
+ - spec/unit/console_logger_spec.rb
98
+ - spec/unit/backend_spec.rb
99
+ - spec/unit/version_spec.rb
100
+ - spec/unit/puppet_logger_spec.rb
101
+ - spec/unit/config_spec.rb
113
102
  - spec/unit/fallback_logger_spec.rb
103
+ - spec/unit/util_spec.rb
114
104
  - spec/spec_helper.rb
@@ -1,31 +0,0 @@
1
- # Allow for safe recursive lookup of values during variable interpolation.
2
- #
3
- # @api private
4
- class Hiera::RecursiveLookup
5
- def initialize(scope, extra_data)
6
- @seen = []
7
- @scope = scope
8
- @extra_data = extra_data
9
- end
10
-
11
- def lookup(name, &block)
12
- if @seen.include?(name)
13
- raise Exception, "Interpolation loop detected in [#{@seen.join(', ')}]"
14
- end
15
- @seen.push(name)
16
- ret = yield(current_value)
17
- @seen.pop
18
- ret
19
- end
20
-
21
- def current_value
22
- name = @seen.last
23
-
24
- scope_val = @scope[name]
25
- if scope_val.nil? || scope_val == :undefined
26
- @extra_data[name]
27
- else
28
- scope_val
29
- end
30
- end
31
- end