[DRE-commits] [SCM] ruby-hiera.git branch, master, updated. debian/1.0.0_rc3-1-5-gccb33a5

Stig Sandbeck Mathisen ssm at debian.org
Tue Feb 5 11:26:08 UTC 2013


The following commit has been merged in the master branch:
commit f9a02b4923be2798aa6d037c81285a122945d209
Author: Stig Sandbeck Mathisen <ssm at debian.org>
Date:   Tue Feb 5 11:51:50 2013 +0100

    Imported Upstream version 1.1.2

diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..55a711c
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,3 @@
+pkg
+test.rb
+ext/packaging
diff --git a/CHANGELOG b/CHANGELOG
deleted file mode 100644
index 4de6f2d..0000000
--- a/CHANGELOG
+++ /dev/null
@@ -1,95 +0,0 @@
-1.0.0rc3
-===
-a1a885a Adding package task liberally copied from puppet-dashboard.
-3527443 Updating apple pkg task to refer to ext directory.
-445a6f2 ext is more appropriate than conf for a dirname.
-ade5567 Adding debian packaging to hiera.
-3ef4f96 Move redhat spec into conf dir, to standardize packaging.
-b6218b9 (maint) Hiera should raise an error when config is missing
-1df7201 Update mac packaging to dynamically generate preflight
-10f930f Add mac packaging to hiera
-22a98ee Remove Puppet parser functions
-0067cd2 (maint) Additional tests for Hiera array and hash lookups
-7312a95 (maint) Add Hiera acceptance tests
-9808a64 (#14514) Use default config when hiera.yaml is missing
-fd644b6 Add require hiera/backend to test
-fe3d509 Remove empty Puppet class definition
-
-1.0.0rc2
-===
-fa3081c Updating hiera.spec, CHANGELOG for Hiera 1.0.0rc1
-6de3d4c Moving CHANGES.txt to CHANGELOG. Updating CHANGELOG with git log from initial commit to v0.3.0 tag.
-dbf9fe3 Update README to reference deb and rpm packages
-f697b7f Updated hiera.spec to include puppet functions and put in the right place.
-540d2d6 (#14460) Add Puppet parser functions
-29c5ad7 Add hiera.spec for building hiera on redhat
-24ef7b9 (#13600) Monkey patch mktmpdir on ruby 1.8.5
-b7b3280 (maint) Make noop logger work on Ruby 1.9.x
-602c526 (maint) Fix failing spec test on Ruby 1.9.3
-82881e3 (#14150) Use tar_gz instead of tar
-7ef2821 (#14148) Add docs to Hiera packaging
-67f91d6 (#14147) Handle lack of rubygems gracefully
-f6c9f5d (#14124) Load rake tasks directly to fix tests for Ruby 1.9.x
-122b891 (#13641) Fix Hiera::Backend#parse_string to support :undefined in extra_data
-e6dea8e Commit caching on YAML Backend
-ddd5b66 Fix VERSION contant in lib/hiera.rb
-50f9771 hiera working on ruby 1.9.2/1.9.3, issue #10975 (http://projects.puppetlabs.com/issues/10975)
-794265f (maint) Code base cleanup, use 2 space indention.
-
-v0.3.0
-===
-
-d3b9c41 Fixes a quoting string issue
-2b6c3e7 Change Rakefile to autoversion
-1e7affb Rspec 2.7 has introduced some non backwards compatible changes that is exposed by using require with full paths.
-d136fc2 Switch branding to Puppet Labs
-731f2ef Fix warnings for rake
-0a53e96 fix failing test after sort was removed
-15fb3bd Do not sort arrays after building them as array data with complex data in them like hashes will fail to sort and raise exceptions
-f296a18 Test cases for #21
-dcf51ce Fixes: Hiera errors on empty yaml files
-d2d59d7 Revising backend bool spec test that nil /= false
-3cd4cec Fixes #15 Hiera return nil for false value
-17a2a98 Adding inventory_service option to scope.
-6ecab35 (#13) Hierarchy includes sub-hierarchy
-79b0d4b Corrected invalid YAML markup.
-c05823a Add specs to verify datatypes are being retained
-dedeb8c Make hiera handle boolean/numeric values correctly instead of just returning nil
-b78b3e4 Add type mismatch error output and test cases
-95e60ce Added additional spec tests for hash.
-f078414 Revising spec test for hash merge.
-9d72afa Hash was merged wrong direction.
-b4a90ba Adding hashes to CHANGES.txt
-90a23be Adding hash spec unit tests
-d1171d7 Adding hash support to hiera and yaml backend
-aa6af39 Fix logic around handling of defaults in array searches.  It used to always return [nil] for unknown data in array searches now it returns the supplied default.
-51a0a57 Fix versioning and autoload the Puppet logger
-fb88a3b Removed :json type from load_scope when parsing YAML format
-3839126 Fix typo
-8b7e036 More 0.2.0 update information
-93711a9 Fix spacing
-e804daf Update readme with information for 0.2.0
-4c990e1 Release 0.2.0
-1977a1e Improve tests based on recent changes
-3683a62 Simplify plugins that reads serialized data from files by moving more to the Backend module
-9d92041 Update changes file
-61e3574 Add Puppet logger plugin
-98a9525 Add array merge searches to the framework and the yaml backend Add array search to the command line Parse %{var}s in Strings, Arrays and Hashes correctly
-19cbf04 Update doco
-0f0837c Add querying facts via mcollective for scope of the CLI
-aeaef32 Remove some stray whitespace Turn a warn message into a debug message to avoid spamming logs
-27d6fd9 Fix /bin/env to /usr/bin/env (#1) Improve gem file
-dde5997 Release 0.1.0
-f69ebb2 Fix verbose checking in the cli Do not return empty sources Improve tests
-6d8130f Small language fix
-23ef93d Show variable expansion in string results
-362710c Add sample data to the readme
-dcc2ad2 Add a CLI query tool
-e3eb8de More todo items
-ced8d33 Add licence and readme
-e5d0106 avoid some debug noise
-dc41bcd Add comments and tests
-19e27c2 Small changes to the yaml backend, add a pluggable logging system and a console logger
-28cdd56 - simplify language by changing precedence with hierarchy - add gem bits - fall through to multiple backends till one provides an answer - make the backend writing process a bit easier
-19e03a7 Working YAML backend
-ca3efeb Add Readme
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..359af6c
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,18 @@
+Puppet - Automating Configuration Management.
+
+Copyright (C) 2012 Puppet Labs Inc
+
+Puppet Labs can be contacted at: info at puppetlabs.com
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+   http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
diff --git a/README.md b/README.md
index e37e2ec..0c18e9c 100644
--- a/README.md
+++ b/README.md
@@ -1,10 +1,11 @@
-What?
-=====
+# Hiera
 
 A simple pluggable Hierarchical Database.
 
-Why?
-====
+-
+**Tutorials:** Check the docs directory for tutorials.
+
+## Why?
 
 Hierarchical data is a good fit for the representation of infrastructure information.
 Consider the example of a typical company with 2 datacenters and on-site development,
@@ -28,7 +29,7 @@ correct answer easily:
                                   \                  /
                            /------------- COMMON -------------\
                           | ntpserver: 1.pool.ntp.org          |
-                          | sysadmin: sysadmin@%{domain}       |
+                          | sysadmin: "sysadmin@%{domain}"     |
                           | classes: users::common             |
                            \----------------------------------/
 </pre>
@@ -48,50 +49,47 @@ This is the data model that extlookup() have promoted in Puppet, Hiera has taken
 data model and extracted it into a standalone project that is pluggable and have a few
 refinements over extlookup.
 
-Enhancements over Extlookup?
-============================
+## Enhancements over Extlookup
 
 Extlookup had just one backend, Hiera can be extended with your own backends and represent
 a few enhancements over the base Extlookup approach thanks to this.
 
-Multiple backends are queried
------------------------------
+### Multiple backends are queried
+
 If you have a YAML and Puppet backend loaded and your users provide module defaults in the
 Puppet backend you can use your YAML data to override the Puppet data.  If the YAML doesnt
-provide an answer the Puppet backend will get an oppertunity to provide an answer.
+provide an answer the Puppet backend will get an opportunity to provide an answer.
+
+### More scope based variable expansion
 
-More scope based variable expansion
------------------------------------
 Extlookup could parse data like %{foo} into a scope lookup for the variable foo.  Hiera
 retains this ability and any Arrays or Hashes will be recursively searched for all strings
 that will then be parsed.
 
 The datadir and defaults are now also subject to variable parsing based on scope.
 
-No CSV support by default
--------------------------
+### No CSV support by default
+
 We have not at present provided a backward compatible CSV backend.  A converter to
 YAML or JSON should be written. When the CSV backend was first chosen for Puppet the
 Puppet language only supports strings and arrays of strings which mapped well to CSV.
 Puppet has become (a bit) better wrt data and can now handle hashes and arrays of hashes
 so it's a good time to retire the old data format.
 
-Array Searches
---------------
+### Array Searches
+
 Hiera can search through all the tiers in a hierarchy and merge the result into a single
 array.  This is used in the hiera-puppet project to replace External Node Classifiers by
 creating a Hiera compatible include function.
 
-Future Enhancements?
-====================
+## Future Enhancements
 
  * More backends should be created
  * A webservice that exposes the data
  * Tools to help maintain the data files.  Ideally this would be Foreman and Dashboard
    with their own backends
 
-Installation?
-=============
+## Installation
 
 Hiera is available as a Gem called _hiera_ and out of the box it comes with just a single
 YAML backend.
@@ -100,8 +98,7 @@ Hiera is also available as a native package via apt (http://apt.puppetlabs.com)
 
 At present JSON (github/ripienaar/hiera-json) and Puppet (hiera-puppet) backends are availble.
 
-Configuration?
-==============
+## Configuration
 
 You can configure Hiera using a YAML file or by providing it Hash data in your code.  There
 isn't a default config path - the CLI script will probably assume _/etc/hiera.yaml_ though.
@@ -111,13 +108,16 @@ A sample configuration file can be seen here:
 
 <pre>
 ---
-:backends: - yaml
-           - puppet
+:backends:
+  - yaml
+  - puppet
 
 :logger: console
 
-:hierarchy: - %{location}
-            - common
+:hierarchy:
+  - "%{location}"
+  - common
+
 :yaml:
    :datadir: /etc/puppet/hieradata
 
@@ -144,12 +144,11 @@ ntpserver: ntp1.dc2.example.com
 _/etc/puppet/hieradata/common.yaml_:
 <pre>
 ---
-sysadmin: sysadmin@%{domain}
+sysadmin: "sysadmin@%{domain}"
 ntpserver: 1.pool.ntp.org
 </pre>
 
-Querying from CLI?
-==================
+## Querying from CLI
 
 You can query your data from the CLI.  By default the CLI expects a config file in _/etc/hiera.yaml_
 but you can pass _--config_ to override that.
@@ -182,8 +181,7 @@ $ hiera -a classes location=dc1
 ["users::common", "users::dc1"]
 </pre>
 
-Querying from code?
-===================
+## Querying from code
 
 This is the same query programatically as in the above CLI example:
 
@@ -205,19 +203,18 @@ hiera = Hiera.new(:config => "/etc/puppet/hiera.yaml")
 puts "ACME Software Version: %s" % [ hiera.lookup("acme_version", "sites/%{location}", scope) ]
 </pre>
 
-Extending?
-==========
+## Extending
 
 There exist 2 backends at present in addition to the bundled YAML one.
 
-JSON
-----
+### JSON
+
 This can be found on github under _ripienaar/hiera-json_.  This is a good example
 of file based backends as Hiera provides a number of helpers to make writing these
 trivial.
 
-Puppet
--------
+### Puppet
+
 This is much more complex and queries the data from the running Puppet state, it's found
 on GitHub under _ripienaar/hiera-puppet_.
 
@@ -230,7 +227,11 @@ When used in Puppet you'd expect Hiera to log using the Puppet infrastructure, t
 plugin includes a Puppet Logger plugin for Hiera that uses the normal Puppet logging
 methods for all logging.
 
-Contact?
-========
+## License
+
+See LICENSE file.
+
+## Support
+
+Please log tickets and issues at our [Projects site](http://projects.puppetlabs.com)
 
-R.I.Pienaar / rip at devco.net / @ripienaar / www.devco.net
diff --git a/Rakefile b/Rakefile
new file mode 100644
index 0000000..41ef3a4
--- /dev/null
+++ b/Rakefile
@@ -0,0 +1,48 @@
+begin
+  require 'rubygems'
+  require 'rspec/core/rake_task'
+rescue LoadError
+end
+
+Dir['tasks/**/*.rake'].each { |t| load t }
+Dir['ext/packaging/tasks/**/*'].sort.each { |t| load t }
+
+build_defs_file = 'ext/build_defaults.yaml'
+if File.exist?(build_defs_file)
+  begin
+    require 'yaml'
+    @build_defaults ||= YAML.load_file(build_defs_file)
+  rescue Exception => e
+    STDERR.puts "Unable to load yaml from #{build_defs_file}:"
+    STDERR.puts e
+  end
+  @packaging_url  = @build_defaults['packaging_url']
+  @packaging_repo = @build_defaults['packaging_repo']
+  raise "Could not find packaging url in #{build_defs_file}" if @packaging_url.nil?
+  raise "Could not find packaging repo in #{build_defs_file}" if @packaging_repo.nil?
+
+  namespace :package do
+    desc "Bootstrap packaging automation, e.g. clone into packaging repo"
+    task :bootstrap do
+      if File.exist?("ext/#{@packaging_repo}")
+        puts "It looks like you already have ext/#{@packaging_repo}. If you don't like it, blow it away with package:implode."
+      else
+        cd 'ext' do
+          %x{git clone #{@packaging_url}}
+        end
+      end
+    end
+    desc "Remove all cloned packaging automation"
+    task :implode do
+      rm_rf "ext/#{@packaging_repo}"
+    end
+  end
+end
+
+if defined?(RSpec::Core::RakeTask)
+  desc "Run all specs"
+  RSpec::Core::RakeTask.new(:test) do |t|
+    t.pattern = 'spec/**/*_spec.rb'
+  end
+end
+
diff --git a/acceptance_tests/tests/yaml_backend/00-setup.rb b/acceptance_tests/tests/yaml_backend/00-setup.rb
new file mode 100644
index 0000000..100e7e1
--- /dev/null
+++ b/acceptance_tests/tests/yaml_backend/00-setup.rb
@@ -0,0 +1,26 @@
+test_name "Hiera setup for YAML backend"
+
+apply_manifest_on master, <<-PP
+file { '/etc/hiera.yaml':
+  ensure  => present,
+  content => '---
+    :backends:
+      - "yaml"
+    :logger: "console"
+    :hierarchy:
+      - "%{fqdn}"
+      - "%{environment}"
+      - "global"
+
+    :yaml:
+      :datadir: "/etc/puppet/hieradata"
+  '
+}
+
+file { '/etc/puppet/hieradata':
+  ensure  => directory,
+  recurse => true,
+  purge   => true,
+  force   => true,
+}
+PP
diff --git a/acceptance_tests/tests/yaml_backend/01-lookup_data_without_a_key.rb b/acceptance_tests/tests/yaml_backend/01-lookup_data_without_a_key.rb
new file mode 100644
index 0000000..5a9c3e6
--- /dev/null
+++ b/acceptance_tests/tests/yaml_backend/01-lookup_data_without_a_key.rb
@@ -0,0 +1,9 @@
+test_name "Lookup data without a key"
+
+step "Try to lookup data without specifying a key"
+
+on master, hiera(""), :acceptable_exit_codes => [1] do
+  assert_output <<-OUTPUT
+    STDERR> Please supply a data item to look up
+  OUTPUT
+end
diff --git a/acceptance_tests/tests/yaml_backend/02-lookup_data_with_no_options.rb b/acceptance_tests/tests/yaml_backend/02-lookup_data_with_no_options.rb
new file mode 100644
index 0000000..6175d08
--- /dev/null
+++ b/acceptance_tests/tests/yaml_backend/02-lookup_data_with_no_options.rb
@@ -0,0 +1,48 @@
+begin test_name "Lookup data using the default options"
+
+step 'Setup'
+apply_manifest_on master, <<-PP
+file { '/etc/puppet/hieradata/global.yaml':
+  ensure  => present,
+  content => "---
+    http_port: 8080
+    ntp_servers: ['0.ntp.puppetlabs.com', '1.ntp.puppetlabs.com']
+    users:
+      pete:
+        uid: 2000
+      tom:
+        uid: 2001
+  "
+}
+PP
+
+step "Try to lookup string data"
+on master, hiera("http_port"), :acceptable_exit_codes => [0] do
+  assert_output <<-OUTPUT
+    STDOUT> 8080
+  OUTPUT
+end
+
+step "Try to lookup array data"
+on master, hiera("ntp_servers"), :acceptable_exit_codes => [0] do
+  assert_output <<-OUTPUT
+    STDOUT> ["0.ntp.puppetlabs.com", "1.ntp.puppetlabs.com"]
+  OUTPUT
+end
+
+step "Try to lookup hash data"
+on master, hiera("users"), :acceptable_exit_codes => [0] do
+  assert_match /tom[^}]+"uid"=>2001}/, result.output
+  assert_match /pete[^}]+"uid"=>2000}/, result.output
+end
+
+ensure step "Teardown"
+apply_manifest_on master, <<-PP
+file { '/etc/puppet/hieradata':
+  ensure  => directory,
+  recurse => true,
+  purge   => true,
+  force   => true,
+}
+PP
+end
diff --git a/acceptance_tests/tests/yaml_backend/03-lookup_data_with_a_scope.rb b/acceptance_tests/tests/yaml_backend/03-lookup_data_with_a_scope.rb
new file mode 100644
index 0000000..377c065
--- /dev/null
+++ b/acceptance_tests/tests/yaml_backend/03-lookup_data_with_a_scope.rb
@@ -0,0 +1,62 @@
+begin test_name "Lookup data with a scope"
+
+step 'Setup'
+apply_manifest_on master, <<-PP
+file { '/etc/puppet/hieradata/global.yaml':
+  ensure  => present,
+  content => "---
+    http_port: 8080
+    ntp_servers: ['0.ntp.puppetlabs.com', '1.ntp.puppetlabs.com']
+    users:
+      pete:
+        uid: 2000
+        gid: 2000
+        shell: '/bin/bash'
+      tom:
+        uid: 2001
+        gid: 2001
+        shell: '/bin/bash'
+  "
+}
+
+file { '/etc/puppet/hieradata/production.yaml':
+  ensure  => present,
+  content => "---
+    http_port: 9090
+    monitor: enable
+    ntp_servers: ['0.ntp.puppetlabs.com', '1.ntp.puppetlabs.com']
+  "
+}
+
+file { '/etc/puppet/scope.yaml':
+  ensure  => present,
+  content => "---
+    environment: production
+  "
+}
+PP
+
+step "Try to lookup string data using a scope from a yaml file"
+on master, hiera('monitor', '--yaml', '/etc/puppet/scope.yaml'),
+  :acceptable_exit_codes => [0] do
+  assert_output <<-OUTPUT
+    STDOUT> enable
+  OUTPUT
+end
+
+# TODO: Add a test for supplying scope from a json file.
+# We need to workout the requirement on the json gem.
+step "Try to lookup string data using a scope from a yaml file"
+
+ensure step "Teardown"
+apply_manifest_on master, <<-PP
+file { '/etc/puppet/hieradata':
+  ensure  => directory,
+  recurse => true,
+  purge   => true,
+  force   => true,
+}
+file { '/etc/puppet/scope.yaml': ensure => absent }
+file { '/etc/puppet/scope.json': ensure => absent }
+PP
+end
diff --git a/acceptance_tests/tests/yaml_backend/04-lookup_data_with_array_search.rb b/acceptance_tests/tests/yaml_backend/04-lookup_data_with_array_search.rb
new file mode 100644
index 0000000..65ec265
--- /dev/null
+++ b/acceptance_tests/tests/yaml_backend/04-lookup_data_with_array_search.rb
@@ -0,0 +1,46 @@
+begin test_name "Lookup data with Array search"
+
+step 'Setup'
+apply_manifest_on master, <<-PP
+file { '/etc/puppet/hieradata/production.yaml':
+  ensure  => present,
+  content => "---
+    ntpservers: ['production.ntp.puppetlabs.com']
+  "
+}
+
+file { '/etc/puppet/hieradata/global.yaml':
+  ensure  => present,
+  content => "---
+    ntpservers: ['global.ntp.puppetlabs.com']
+  "
+}
+
+file { '/etc/puppet/scope.yaml':
+  ensure  => present,
+  content => "---
+    environment: production
+  "
+}
+PP
+
+step "Try to lookup data using array search"
+on master, hiera('ntpservers', '--yaml', '/etc/puppet/scope.yaml', '--array'),
+  :acceptable_exit_codes => [0] do
+  assert_output <<-OUTPUT
+    STDOUT> ["production.ntp.puppetlabs.com", "global.ntp.puppetlabs.com"]
+  OUTPUT
+end
+
+ensure step "Teardown"
+apply_manifest_on master, <<-PP
+file { '/etc/puppet/hieradata':
+  ensure  => directory,
+  recurse => true,
+  purge   => true,
+  force   => true,
+}
+file { '/etc/puppet/scope.yaml': ensure => absent }
+file { '/etc/puppet/scope.json': ensure => absent }
+PP
+end
diff --git a/acceptance_tests/tests/yaml_backend/05-lookup_data_with_hash_search.rb b/acceptance_tests/tests/yaml_backend/05-lookup_data_with_hash_search.rb
new file mode 100644
index 0000000..8baffae
--- /dev/null
+++ b/acceptance_tests/tests/yaml_backend/05-lookup_data_with_hash_search.rb
@@ -0,0 +1,49 @@
+begin test_name "Lookup data with Hash search"
+
+step 'Setup'
+apply_manifest_on master, <<-PP
+file { '/etc/puppet/hieradata/production.yaml':
+  ensure  => present,
+  content => "---
+    users:
+      joe:
+        uid: 1000
+  "
+}
+
+file { '/etc/puppet/hieradata/global.yaml':
+  ensure  => present,
+  content => "---
+    users:
+      pete:
+        uid: 1001
+  "
+}
+
+file { '/etc/puppet/scope.yaml':
+  ensure  => present,
+  content => "---
+    environment: production
+  "
+}
+PP
+
+step "Try to lookup data using hash search"
+on master, hiera('users', '--yaml', '/etc/puppet/scope.yaml', '--hash'),
+  :acceptable_exit_codes => [0] do
+  assert_match /joe[^}]+"uid"=>1000}/, result.output
+  assert_match /pete[^}]+"uid"=>1001}/, result.output
+end
+
+ensure step "Teardown"
+apply_manifest_on master, <<-PP
+file { '/etc/puppet/hieradata':
+  ensure  => directory,
+  recurse => true,
+  purge   => true,
+  force   => true,
+}
+file { '/etc/puppet/scope.yaml': ensure => absent }
+file { '/etc/puppet/scope.json': ensure => absent }
+PP
+end
diff --git a/bin/hiera b/bin/hiera
index 984d3ec..ddd4daa 100755
--- a/bin/hiera
+++ b/bin/hiera
@@ -11,16 +11,23 @@
 #
 # $ hiera release 'rel/%{location}' location=dc2 --yaml some.node.yaml
 
-begin
-  require 'rubygems'
-rescue LoadError
+# Bundler and rubygems maintain a set of directories from which to
+# load gems. If Bundler is loaded, let it determine what can be
+# loaded. If it's not loaded, then use rubygems. But do this before
+# loading any hiera code, so that our gem loading system is sane.
+if not defined? ::Bundler
+  begin
+    require 'rubygems'
+  rescue LoadError
+  end
 end
 require 'hiera'
+require 'hiera/util'
 require 'optparse'
 
 options = {
   :default => nil,
-  :config  => "/etc/hiera.yaml",
+  :config  => File.join(Hiera::Util.config_dir, 'hiera.yaml'),
   :scope   => {},
   :key     => nil,
   :verbose => false,
@@ -106,6 +113,8 @@ def load_scope(source, type=:yaml)
 end
 
 OptionParser.new do |opts|
+  opts.banner = "Usage: hiera [options] key [default value] [variable='text'...]\n\nThe default value will be used if no value is found for the key. Scope variables\nwill be interpolated into %{variable} placeholders in the hierarchy and in\nreturned values.\n\n"
+
   opts.on("--version", "-V", "Version information") do
     puts Hiera.version
     exit
@@ -115,11 +124,11 @@ OptionParser.new do |opts|
     options[:verbose] = true
   end
 
-  opts.on("--array", "-a", "Array search") do
+  opts.on("--array", "-a", "Return all values as an array") do
     options[:resolution_type] = :array
   end
 
-  opts.on("--hash", "-h", "Hash search") do
+  opts.on("--hash", "-h", "Return all values as a hash") do
     options[:resolution_type] = :hash
   end
 
@@ -150,7 +159,7 @@ OptionParser.new do |opts|
     end
   end
 
-  opts.on("--mcollective IDENTITY", "-m", "Retrieve facts from a node via mcollective as scope") do |v|
+  opts.on("--mcollective IDENTITY", "-m", "Use facts from a node (via mcollective) as scope") do |v|
     begin
       options[:scope] = load_scope(v, :mcollective)
     rescue Exception => e
@@ -159,7 +168,7 @@ OptionParser.new do |opts|
     end
   end
 
-  opts.on("--inventory_service IDENTITY", "-i", "Retrieve facts for a node via Puppet's inventory service as scope") do |v|
+  opts.on("--inventory_service IDENTITY", "-i", "Use facts from a node (via Puppet's inventory service) as scope") do |v|
     begin
       options[:scope] = load_scope(v, :inventory_service)
     rescue Exception => e
diff --git a/docs/images/hiera_hierarchy_resolution.png b/docs/images/hiera_hierarchy_resolution.png
new file mode 100644
index 0000000..1b37cf8
Binary files /dev/null and b/docs/images/hiera_hierarchy_resolution.png differ
diff --git a/docs/images/hiera_hierarchy_resolution_empty_scope.png b/docs/images/hiera_hierarchy_resolution_empty_scope.png
new file mode 100644
index 0000000..217839b
Binary files /dev/null and b/docs/images/hiera_hierarchy_resolution_empty_scope.png differ
diff --git a/docs/tutorials/getting_started.md b/docs/tutorials/getting_started.md
new file mode 100644
index 0000000..04b8912
--- /dev/null
+++ b/docs/tutorials/getting_started.md
@@ -0,0 +1,113 @@
+# Getting Started
+
+Hiera is a simple hierarchal database which provides an easy to use interface
+for looking up data using a key.
+
+    $ hiera puppetlabs_home_page
+    http://puppetlabs.com
+
+## Installation
+
+We are going to install Hiera using Rubygems, so now is a good time to make
+sure you meet the prerequisites.
+
+### Prerequisites
+
+ * Ruby 1.8.5+
+ * Rubygems 1.3.0+
+
+### Installing Hiera via Rubygems
+
+    $ gem install hiera
+    Successfully installed hiera-0.3.0
+    1 gem installed
+    Installing ri documentation for hiera-0.3.0...
+    Installing RDoc documentation for hiera-0.3.0...
+
+Make sure we can run the hiera command:
+
+    $ hiera -v
+    0.3.0
+
+-
+
+**Note:** Some Linux distributions such as Debian squeeze do not put the gem bin
+directory (`/var/lib/gems/1.8/bin`) in your PATH by default. You may have
+to call hiera using the full path:
+
+    $ /var/lib/gems/1.8/bin/hiera -v
+    0.3.0
+
+## Configuration
+
+Before using Hiera we need to create a configuration file. By default Hiera
+attempts to load `hiera.yaml` from the `/etc/` directory. Lets create that
+file now:
+
+    $ vim /etc/hiera.yaml
+    ---
+    :backends:
+      - yaml
+
+    :hierarchy:
+      - global
+
+    :yaml:
+      :datadir: /var/lib/hiera/data
+
+-
+
+**Note:** If Hiera cannot locate `/etc/hiera.yaml` you will receive the follow
+error when trying to lookup a value:
+
+    $ hiera key
+    Failed to start Hiera: RuntimeError: Config file /etc/hiera.yaml not found
+
+You can specify a different configuration file using the `--config` option:
+
+    $ hiera --config ~/hiera.yaml key
+
+## Adding data
+
+With configuration out of the way, lets add some data. The yaml backend
+expects to find data files under the `datadir` we configured earlier.
+
+Create the `/var/lib/hiera/data` data directory:
+
+    $ mkdir -p /var/lib/hiera/data
+
+For each source in the `hierarchy`, the yaml backend will search for a
+corresponding YAML file under the `datadir`.
+
+For example, our `hierarchy` consists of a single source named `global`. The
+yaml backend will look for `/var/lib/hiera/data/global.yaml`, and if missing
+skips it and move on to the next source in the hierarchy.
+
+Lets add some data to the `global` source:
+
+    $ vim /var/lib/hiera/data/global.yaml
+    ---
+    driftfile: '/etc/ntp/drift'
+    ntpservers:
+      - '0.north-america.pool.ntp.org'
+      - '1.north-america.pool.ntp.org'
+
+## Looking up data
+
+Now that we have our configuration setup and some data, lets lookup the
+'driftfile' key:
+
+    $ /var/lib/gems/1.8/bin/hiera driftfile
+    /etc/ntp/drift
+
+We get extacaly what we expected, '/etc/ntp/drift'.
+
+Running the lookup command with the `--debug` flag, we can see the details
+of how Hiera lookups data:
+
+    $ /var/lib/gems/1.8/bin/hiera driftfile --debug
+    DEBUG: Thu Jun 28 09:54:04 -0400 2012: Hiera YAML backend starting
+    DEBUG: Thu Jun 28 09:54:04 -0400 2012: Looking up driftfile in YAML backend
+    DEBUG: Thu Jun 28 09:54:04 -0400 2012: Looking for data source global
+    /etc/ntp/drift
+
diff --git a/docs/tutorials/hierarchies_sources_and_scope.md b/docs/tutorials/hierarchies_sources_and_scope.md
new file mode 100644
index 0000000..3b64290
--- /dev/null
+++ b/docs/tutorials/hierarchies_sources_and_scope.md
@@ -0,0 +1,123 @@
+# Hierarchies, Sources, and Scope
+
+The key to mastering Hiera is understanding the following concepts:
+
+ * Hierarchies
+ * Sources
+ * Scope
+
+## Hierarchies
+
+At the very core of Hiera are the data hierarchies, which are made up of
+sources. Hierarchies are specified in Hiera configuration file `hiera.yaml` via the
+`:hierarchy:` array.
+
+    :hierarchy:
+      - "%{certname}"
+      - "%{environment}"
+      - default
+
+There are three sources in the above hierarchy, `%{certname}`, `%{environment}`,
+and `default`. The first two sources, `%{certname}` and `%{environment}`,
+represent dynamic sources which will be resolved at runtime. The third source
+`default` is static.
+
+
+When looking up a key Hiera iterates through each source in the hierarchy
+starting with the first one in the list. In our case `%{certname}`. There is
+no limit to the number of sources you can have. But lets not go crazy; try and
+keep your hierarchy below 5 - 6 levels deep. Any more than this you should
+start thinking about custom facts or how your data is organized.
+
+### Order is important
+
+Hiera uses the priority resolution type by default. This means Hiera stops at
+the first source in the hierarchy that provides a non `nil` answer. The
+behavior is a slightly different for the array and hash resolution types. Every
+scope in the hierarchy will be searched, but data is appended not overridden!
+
+## Sources
+
+Each level of the hierarchy is represented by a source which comes in two
+flavors, static and dynamic.
+
+### Static sources
+
+A source is considered static when it appears in the hierarchy as a simple
+string.
+
+    :hierarchy:
+      - default
+
+-
+You should consider using a static source when you want a certain level in
+the hierarchy to apply to all nodes.
+
+### Dynamic sources
+
+A source is considered dynamic when it appears in the hierarchy as a string
+enclosed between `%{}` like this:
+
+    :hierarchy:
+      - %{certname}
+
+Dynamic sources are interpolated by Hiera at runtime.
+
+-
+You should consider using a dynamic source when you want to provide different
+data based on Facter Facts.
+
+## Scope
+
+A scope is a collection of key/value pairs:
+
+    certname: agent.puppetlabs.com
+    environment: production
+    operatingsystem: Debian
+
+If you are thinking scopes look a lot like Facter Facts you are on to
+something. Hiera was designed around Facter Facts being the primary input
+for scope.
+
+### Source interpolation
+
+Hiera uses the scope when interpolating sources in the hierarchy.
+
+<img src='https://github.com/kelseyhightower/hiera/raw/maint/1.0rc/add_getting_started_tutorial/docs/images/hiera_hierarchy_resolution.png' />
+
+Scopes can be empty, and when they are, dynamic sources are excluded from the
+hierarchy at run time.
+
+<img src='https://github.com/kelseyhightower/hiera/raw/maint/1.0rc/add_getting_started_tutorial/docs/images/hiera_hierarchy_resolution_empty_scope.png' />
+
+### Feeding Hiera your scope
+
+You can provide Hiera a scope via the command line using the `--yaml` or
+`--json` options.
+
+For example:
+
+If we had the following scope:
+
+    $ cat /tmp/scope.yaml
+    ---
+    certname: agent.example.com
+    environment: production
+
+
+
+You can feed it to Hiera like this:
+
+    $ hiera --yaml /tmp/scope.yaml driftfile
+    /etc/ntp/drift
+
+-
+**Note:** If you run into the follow error, you need to make sure Puppet is installed:
+
+    Could not load YAML scope: LoadError: no such file to load -- puppet
+
+The reason for this is that the scope yaml file could have been produced by
+Puppet, and contained serialized objects. Since it would be desirable to use 
+Hiera without Puppet, this restrict will be removed in the future.
+
+
diff --git a/ext/build_defaults.yaml b/ext/build_defaults.yaml
new file mode 100644
index 0000000..320704b
--- /dev/null
+++ b/ext/build_defaults.yaml
@@ -0,0 +1,23 @@
+---
+packaging_url: 'git://github.com/puppetlabs/packaging.git --branch=master'
+packaging_repo: 'packaging'
+default_cow: 'base-squeeze-i386.cow'
+cows: 'base-lucid-i386.cow base-natty-i386.cow base-oneiric-i386.cow base-precise-i386.cow base-quantal-i386.cow base-sid-i386.cow base-squeeze-i386.cow base-stable-i386.cow base-testing-i386.cow base-unstable-i386.cow base-wheezy-i386.cow'
+pbuild_conf: '/etc/pbuilderrc'
+packager: 'puppetlabs'
+gpg_name: 'info at puppetlabs.com'
+gpg_key: '4BD6EC30'
+sign_tar: FALSE
+# a space separated list of mock configs
+final_mocks: 'pl-5-i386 pl-6-i386 fedora-16-i386 fedora-17-i386'
+rc_mocks: 'pl-5-i386-dev pl-6-i386-dev fedora-16-i386-dev fedora-17-i386-dev'
+build_gem: TRUE
+build_dmg: TRUE
+yum_host: 'burji.puppetlabs.com'
+yum_repo_path: '/opt/repository/yum/'
+apt_host: 'burji.puppetlabs.com'
+apt_repo_url: 'http://apt.puppetlabs.com'
+apt_repo_path: '/opt/repository/incoming'
+ips_repo: '/var/pkgrepo'
+ips_store: '/opt/repository'
+ips_host: 'solaris-11-ips-repo.acctest.dc1.puppetlabs.net'
diff --git a/ext/debian/changelog.erb b/ext/debian/changelog.erb
new file mode 100644
index 0000000..b178c6e
--- /dev/null
+++ b/ext/debian/changelog.erb
@@ -0,0 +1,23 @@
+hiera (<%= @debversion %>) lucid maverick natty lenny squeeze precise wheezy sid unstable; urgency=low
+
+  * update to version <%= @debversion %>
+
+ -- Puppet Labs Release  <info at puppetlabs.com>  <%= Time.now.strftime("%a, %d %b %Y %H:%M:%S %z")  %>
+
+hiera (0.99+1.0.0rc2-1puppet1) unstable; urgency=low
+
+  * Release of 1.0.0rc2
+
+ -- Matthaus Litteken <matthaus at puppetlabs.com>  Tue, 15 May 2012 04:45:08 +0000
+
+hiera (0.99+1.0.0rc1-1puppet1) unstable; urgency=low
+
+  * Release of 1.0.0rc1
+
+ -- Puppet Labs Release Key (Puppet Labs Release Key) <info at puppetlabs.com>  Mon, 14 May 2012 23:55:54 +0000
+
+hiera (0.3.0.24-1) unstable; urgency=low
+
+  * Initial release of upstream 0.3.0.24
+
+ -- Puppet Labs Release Key (Puppet Labs Release Key) <info at puppetlabs.com>  Fri, 04 May 2012 20:43:22 +0000
diff --git a/debian/compat b/ext/debian/compat
similarity index 100%
copy from debian/compat
copy to ext/debian/compat
diff --git a/ext/debian/control b/ext/debian/control
new file mode 100644
index 0000000..2f160aa
--- /dev/null
+++ b/ext/debian/control
@@ -0,0 +1,13 @@
+Source: hiera
+Section: utils
+Priority: extra
+Maintainer: Puppet Labs <info at puppetlabs.com>
+Build-Depends: debhelper (>= 7.0.0), cdbs, quilt, ruby | ruby-interpreter
+Standards-Version: 3.9.2
+Homepage: http://projects.puppetlabs.com/projects/hiera
+
+Package: hiera
+Architecture: all
+Depends: ${shlibs:Depends}, ${misc:Depends}, ruby | ruby-interpreter, libjson-ruby | ruby-json
+Description: A simple pluggable Hierarchical Database.
+	Hiera is a simple pluggable Hierarchical Database.
diff --git a/ext/debian/copyright b/ext/debian/copyright
new file mode 100644
index 0000000..a27ad7b
--- /dev/null
+++ b/ext/debian/copyright
@@ -0,0 +1 @@
+/usr/share/common-licenses/Apache-2.0
diff --git a/ext/debian/rules b/ext/debian/rules
new file mode 100755
index 0000000..84d7e4e
--- /dev/null
+++ b/ext/debian/rules
@@ -0,0 +1,35 @@
+#!/usr/bin/make -f
+# -*- makefile -*-
+# Sample debian/rules that uses debhelper.
+# This file was originally written by Joey Hess and Craig Small.
+# As a special exception, when this file is copied by dh-make into a
+# dh-make output file, you may use that output file without restriction.
+# This special exception was added by Craig Small in version 0.37 of dh-make.
+
+# Uncomment this to turn on verbose mode.
+#export DH_VERBOSE=1
+
+include /usr/share/cdbs/1/rules/debhelper.mk
+include /usr/share/cdbs/1/rules/patchsys-quilt.mk
+
+BUILD_ROOT=$(DESTDIR)/$(CURDIR)/debian/$(cdbs_curpkg)
+LIBDIR=$(shell /usr/bin/ruby -rrbconfig -e 'puts RbConfig::CONFIG["vendordir"]')
+BIN_DIR=$(shell /usr/bin/ruby -rrbconfig -e 'puts RbConfig::CONFIG["bindir"]')
+RUBYLIB=$(BUILD_ROOT)/$(LIBDIR)
+RUBYBIN=$(BUILD_ROOT)/$(BIN_DIR)
+DOC_DIR=$(BUILD_ROOT)/usr/share/doc/hiera/
+DATA_DIR=$(BUILD_ROOT)/var/lib/hiera
+
+install/hiera::
+	mkdir -p $(RUBYLIB)
+	mkdir -p $(RUBYBIN)
+	mkdir -p $(DOC_DIR)
+	mkdir -p $(DATA_DIR)
+	mkdir -p $(BUILD_ROOT)/etc
+	cp -pr  lib/hiera $(RUBYLIB)
+	cp -p lib/hiera.rb $(RUBYLIB)
+	cp -p  bin/* $(RUBYBIN)
+	cp -pr ext/hiera.yaml $(BUILD_ROOT)/etc
+	cp -p COPYING README.md $(DOC_DIR)
+
+clean::
diff --git a/debian/source/format b/ext/debian/source/format
similarity index 100%
copy from debian/source/format
copy to ext/debian/source/format
diff --git a/ext/hiera.yaml b/ext/hiera.yaml
new file mode 100644
index 0000000..c005288
--- /dev/null
+++ b/ext/hiera.yaml
@@ -0,0 +1,15 @@
+---
+:backends:
+  - yaml
+:hierarchy:
+  - defaults
+  - %{clientcert}
+  - %{environment}
+  - global
+
+:yaml:
+# datadir is empty here, so hiera uses its defaults:
+# - /var/lib/hiera on *nix
+# - %CommonAppData%\PuppetLabs\hiera\var on Windows
+# When specifying a datadir, make sure the directory exists.
+  :datadir:
diff --git a/ext/ips/hiera.p5m.erb b/ext/ips/hiera.p5m.erb
new file mode 100644
index 0000000..37c8a3d
--- /dev/null
+++ b/ext/ips/hiera.p5m.erb
@@ -0,0 +1,10 @@
+set name=pkg.fmri value=pkg://puppetlabs.com/application/<%=@name%>@<%=@ipsversion%>
+set name=pkg.summary value="<%=@summary%>"
+set name=pkg.human-version value="<%=@version%>"
+set name=pkg.description value="<%=@description%>"
+set name=info.classification value="org.opensolaris.category.2008:Applications/System Utilities"
+set name=org.opensolaris.consolidation value="puppet"
+set name=description value="<%=@description%>"
+set name=variant.opensolaris.zone value=global value=nonglobal
+set name=variant.arch value=sparc value=i386
+license hiera.license license="Apache v2.0"
diff --git a/ext/ips/rules b/ext/ips/rules
new file mode 100755
index 0000000..cd87e8d
--- /dev/null
+++ b/ext/ips/rules
@@ -0,0 +1,17 @@
+#!/usr/bin/make -f
+
+LIBDIR=$(shell /usr/bin/ruby18 -rrbconfig -e 'puts RbConfig::CONFIG["rubylibdir"]')
+DESTDIR=$(CURDIR)/pkg/ips/proto
+
+install/hiera::
+	mkdir -p $(DESTDIR)/$(LIBDIR)
+	mkdir -p $(DESTDIR)/usr/bin
+	mkdir -p $(DESTDIR)/usr/share/doc/hiera
+	mkdir -p $(DESTDIR)/var/lib/hiera
+	mkdir -p $(DESTDIR)/etc
+	cp -pr lib/hiera $(DESTDIR)/$(LIBDIR)
+	cp -p lib/hiera.rb $(DESTDIR)/$(LIBDIR)
+	cp -p bin/* $(DESTDIR)/usr/bin
+	cp -pr ext/hiera.yaml $(DESTDIR)/etc
+	cp -p COPYING README.md $(DESTDIR)/usr/share/doc/hiera
+
diff --git a/ext/ips/transforms b/ext/ips/transforms
new file mode 100644
index 0000000..e4a8e5b
--- /dev/null
+++ b/ext/ips/transforms
@@ -0,0 +1,20 @@
+<transform file dir link hardlink path=usr/share/man/.+(/.+)? -> default facet.doc.man true>
+<transform file path=usr/share/man/.+(/.+)? -> add restart_fmri svc:/application/man-index:default>
+
+# drop user
+<transform dir path=usr$->drop>
+<transform dir path=usr/bin$->drop>
+<transform dir path=etc$->drop>
+<transform dir path=var$->drop>
+<transform dir path=var/lib$->drop>
+<transform dir path=usr/share$->drop>
+<transform dir path=usr/share/doc$->drop>
+<transform dir path=usr/ruby$->drop>
+<transform dir path=usr/ruby/1.8$->drop>
+<transform dir path=usr/ruby/1.8/lib$->drop>
+<transform dir path=usr/ruby/1.8/lib/ruby$->drop>
+<transform dir path=usr/ruby/1.8/lib/ruby/1.8$->drop>
+
+
+# saner dependencies
+<transform depend -> edit fmri "@[^ \t\n\r\f\v]*" "">
diff --git a/ext/osx/file_mapping.yaml b/ext/osx/file_mapping.yaml
new file mode 100644
index 0000000..99fc090
--- /dev/null
+++ b/ext/osx/file_mapping.yaml
@@ -0,0 +1,32 @@
+directories:
+  lib:
+    path: 'usr/lib/ruby/site_ruby/1.8'
+    owner: 'root'
+    group: 'wheel'
+    perms: '0644'
+  bin:
+    path: 'usr/bin'
+    owner: 'root'
+    group: 'wheel'
+    perms: '0755'
+  hiera:
+    path: 'var/lib/hiera'
+    owner: 'root'
+    group: 'wheel'
+    perms: '0644'
+  etc:
+    path: 'etc'
+    owner: 'root'
+    group: 'wheel'
+    perms: '0644'
+files:
+  '[A-Z]*':
+    path: 'usr/share/doc/hiera'
+    owner: 'root'
+    group: 'wheel'
+    perms: '0644'
+  'ext/hiera.yaml':
+    path: 'etc'
+    owner: 'root'
+    group: 'wheel'
+    perms: '0644'
diff --git a/ext/osx/preflight.erb b/ext/osx/preflight.erb
new file mode 100644
index 0000000..93ecc00
--- /dev/null
+++ b/ext/osx/preflight.erb
@@ -0,0 +1,30 @@
+#!/bin/bash
+#
+# Make sure that old hiera cruft is removed
+# This also allows us to downgrade facter as
+# it's more likely that installing old versions
+# over new will cause issues.
+#
+# ${3} is the destination volume so that this works correctly
+# when being installed to volumes other than the current OS.
+
+<% begin %>
+<%  require 'rubygems' %>
+<% rescue LoadError %>
+<% end %>
+<% require 'rake' %>
+
+# remove libdir
+<% Dir.chdir("lib") %>
+<% FileList["**/*"].select {|i| File.file?(i)}.each do |file| %>
+/bin/rm -Rf "${3}<%= @apple_libdir %>/<%=file%>"
+<% end %>
+# remove bin files
+<% Dir.chdir("../bin") %>
+<% FileList["**/*"].select {|i| File.file?(i)}.each do |file| %>
+/bin/rm -Rf "${3}<%= @apple_bindir %>/<%=file%>"
+<% end %>
+<% Dir.chdir("..") %>
+
+# remove old doc files
+/bin/rm -Rf "${3}<%= @apple_docdir %>/<%=@package_name%>"
diff --git a/ext/osx/prototype.plist.erb b/ext/osx/prototype.plist.erb
new file mode 100644
index 0000000..e3afe30
--- /dev/null
+++ b/ext/osx/prototype.plist.erb
@@ -0,0 +1,38 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist>
+<dict>
+	<key>CFBundleIdentifier</key>
+	<string><%= @title %></string>
+	<key>CFBundleShortVersionString</key>
+	<string><%= @version %></string>
+	<key>IFMajorVersion</key>
+	<integer><%= @package_major_version %></integer>
+	<key>IFMinorVersion</key>
+	<integer><%= @package_minor_version %></integer>
+	<key>IFPkgBuildDate</key>
+	<date><%= @build_date %></date>
+	<key>IFPkgFlagAllowBackRev</key>
+	<false/>
+	<key>IFPkgFlagAuthorizationAction</key>
+	<string>RootAuthorization</string>
+	<key>IFPkgFlagDefaultLocation</key>
+	<string>/</string>
+	<key>IFPkgFlagFollowLinks</key>
+	<true/>
+	<key>IFPkgFlagInstallFat</key>
+	<false/>
+	<key>IFPkgFlagIsRequired</key>
+	<false/>
+	<key>IFPkgFlagOverwritePermissions</key>
+	<false/>
+	<key>IFPkgFlagRelocatable</key>
+	<false/>
+	<key>IFPkgFlagRestartAction</key>
+	<string><%= @pm_restart %></string>
+	<key>IFPkgFlagRootVolumeOnly</key>
+	<true/>
+	<key>IFPkgFlagUpdateInstalledLanguages</key>
+	<false/>
+</dict>
+</plist>
diff --git a/ext/project_data.yaml b/ext/project_data.yaml
new file mode 100644
index 0000000..b034577
--- /dev/null
+++ b/ext/project_data.yaml
@@ -0,0 +1,17 @@
+---
+project: 'hiera'
+author: 'Puppet Labs'
+email: 'info at puppetlabs.com'
+homepage: 'https://github.com/puppetlabs/hiera'
+summary: 'Light weight hierarchical data store'
+description: 'A pluggable data store for hierarcical data'
+version_file: 'lib/hiera.rb'
+# files and gem_files are space separated lists
+files: '[A-Z]* ext lib bin spec acceptance_tests'
+gem_files: '{bin,lib}/**/* COPYING README.md LICENSE'
+gem_require_path: 'lib'
+gem_test_files: 'spec/**/*'
+gem_executables: 'hiera'
+gem_runtime_dependencies:
+  json_pure:
+gem_default_executables: 'hiera'
diff --git a/ext/redhat/hiera.spec.erb b/ext/redhat/hiera.spec.erb
new file mode 100644
index 0000000..73c1b76
--- /dev/null
+++ b/ext/redhat/hiera.spec.erb
@@ -0,0 +1,80 @@
+# Fedora 17 ships with ruby 1.9, which uses vendorlibdir instead
+# of sitelibdir
+%if 0%{?fedora} >= 17
+%global hiera_libdir   %(ruby -rrbconfig -e 'puts RbConfig::CONFIG["vendorlibdir"]')
+%else
+%global hiera_libdir   %(ruby -rrbconfig -e 'puts RbConfig::CONFIG["sitelibdir"]')
+%endif
+
+%if 0%{?rhel} == 5
+%global _sharedstatedir %{_prefix}/lib
+%endif
+
+# VERSION is subbed out during rake srpm process
+%global realversion <%= @version %>
+%global rpmversion <%= @rpmversion %>
+
+Name:           hiera
+Version:        %{rpmversion}
+Release:        <%= @rpmrelease -%>%{?dist}
+Summary:        A simple pluggable Hierarchical Database
+Vendor:         %{?_host_vendor}
+Group:          System Environment/Base
+License:        ASL 2.0
+URL:            http://projects.puppetlabs.com/projects/%{name}/
+Source0:        http://downloads.puppetlabs.com/%{name}/%{name}-%{realversion}.tar.gz
+BuildRoot:      %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n)
+BuildArch:      noarch
+BuildRequires:  ruby >= 1.8.5
+Requires:       ruby(abi) >= 1.8
+Requires:       ruby >= 1.8.5
+Requires:       rubygem-json
+
+%description
+A simple pluggable Hierarchical Database.
+
+%prep
+%setup -q  -n %{name}-%{realversion}
+
+
+%build
+
+
+%install
+rm -rf $RPM_BUILD_ROOT
+mkdir -p $RPM_BUILD_ROOT/%{hiera_libdir}
+mkdir -p $RPM_BUILD_ROOT/%{_bindir}
+mkdir -p $RPM_BUILD_ROOT/%{_sysconfdir}
+mkdir -p $RPM_BUILD_ROOT/%{_sharedstatedir}/hiera
+cp -pr lib/hiera $RPM_BUILD_ROOT/%{hiera_libdir}
+cp -pr lib/hiera.rb $RPM_BUILD_ROOT/%{hiera_libdir}
+install -p -m0755 bin/hiera $RPM_BUILD_ROOT/%{_bindir}
+install -p -m0644 ext/hiera.yaml $RPM_BUILD_ROOT/%{_sysconfdir}
+
+%clean
+rm -rf $RPM_BUILD_ROOT
+
+
+%files
+%defattr(-,root,root,-)
+%{_bindir}/hiera
+%{hiera_libdir}/hiera.rb
+%{hiera_libdir}/hiera
+%config(noreplace) %{_sysconfdir}/hiera.yaml
+%{_sharedstatedir}/hiera
+%doc COPYING README.md
+
+
+%changelog
+* <%= Time.now.strftime("%a %b %d %Y") %> Puppet Labs Release <info at puppetlabs.com> -  <%= @rpmversion %>-<%= @rpmrelease %>
+- Build for <%= @version %>
+
+* Mon May 14 2012 Matthaus Litteken <matthaus at puppetlabs.com> - 1.0.0-0.1rc2
+- 1.0.0rc2 release
+
+* Mon May 14 2012 Matthaus Litteken <matthaus at puppetlabs.com> - 1.0.0-0.1rc1
+- 1.0.0rc1 release
+
+* Thu May 03 2012 Matthaus Litteken <matthaus at puppetlabs.com> - 0.3.0.28-1
+- Initial Hiera Packaging. Upstream version 0.3.0.28
+
diff --git a/lib/hiera.rb b/lib/hiera.rb
index 2f7608b..c1707f3 100644
--- a/lib/hiera.rb
+++ b/lib/hiera.rb
@@ -1,13 +1,10 @@
-begin
-  require 'rubygems'
-rescue LoadError
-end
 require 'yaml'
 
 class Hiera
-  VERSION = "1.0.0"
+  VERSION = "1.1.2"
 
   autoload :Config,         "hiera/config"
+  autoload :Util,           "hiera/util"
   autoload :Backend,        "hiera/backend"
   autoload :Console_logger, "hiera/console_logger"
   autoload :Puppet_logger,  "hiera/puppet_logger"
@@ -45,7 +42,7 @@ class Hiera
   # If the config option is a string its assumed to be a filename,
   # else a hash of what would have been in the YAML config file
   def initialize(options={})
-    options[:config] ||= "/etc/hiera.yaml"
+    options[:config] ||= File.join(Util.config_dir, 'hiera.yaml')
 
     @config = Config.load(options[:config])
 
@@ -65,3 +62,4 @@ class Hiera
     Backend.lookup(key, default, scope, order_override, resolution_type)
   end
 end
+
diff --git a/lib/hiera/backend.rb b/lib/hiera/backend.rb
index 0f2f77f..27cc1c6 100644
--- a/lib/hiera/backend.rb
+++ b/lib/hiera/backend.rb
@@ -1,3 +1,5 @@
+require 'hiera/util'
+
 class Hiera
   module Backend
     class << self
@@ -6,7 +8,7 @@ class Hiera
       # subject to variable expansion based on scope
       def datadir(backend, scope)
         backend = backend.to_sym
-        default = "/var/lib/hiera"
+        default = Hiera::Util.var_dir
 
         if Config.include?(backend)
           parse_string(Config[backend][:datadir] || default, scope)
@@ -31,18 +33,6 @@ class Hiera
         return file
       end
 
-      # Returns an appropriate empty answer dependant on resolution type
-      def empty_answer(resolution_type)
-        case resolution_type
-        when :array
-          return []
-        when :hash
-          return {}
-        else
-          return nil
-        end
-      end
-
       # Constructs a list of data sources to search
       #
       # If you give it a specific hierarchy it will just use that
@@ -87,20 +77,22 @@ class Hiera
 
         if tdata.is_a?(String)
           while tdata =~ /%\{(.+?)\}/
-            var = $1
-
-            val = ""
-
-            # Puppet can return :undefined for unknown scope vars,
-            # If it does then we still need to evaluate extra_data
-            # before returning an empty string.
-            if scope[var] && scope[var] != :undefined
-                val = scope[var]
-            elsif extra_data[var]
-                val = extra_data[var]
-            end
-
-            tdata.gsub!(/%\{#{var}\}/, val)
+            begin
+              var = $1
+
+              val = ""
+
+              # Puppet can return :undefined for unknown scope vars,
+              # If it does then we still need to evaluate extra_data
+              # before returning an empty string.
+              if scope[var] && scope[var] != :undefined
+                  val = scope[var]
+              elsif extra_data[var]
+                  val = extra_data[var]
+              end
+            end until val != "" || var !~ /::(.+)/
+
+            tdata.gsub!(/%\{(::)?#{var}\}/, val)
           end
         end
 
@@ -164,16 +156,30 @@ class Hiera
         Config[:backends].each do |backend|
           if constants.include?("#{backend.capitalize}_backend") || constants.include?("#{backend.capitalize}_backend".to_sym)
             @backends[backend] ||= Backend.const_get("#{backend.capitalize}_backend").new
-            answer = @backends[backend].lookup(key, scope, order_override, resolution_type)
-
-            break if answer
+            new_answer = @backends[backend].lookup(key, scope, order_override, resolution_type)
+
+            if not new_answer.nil?
+              case resolution_type
+              when :array
+                raise Exception, "Hiera type mismatch: expected Array and got #{new_answer.class}" unless new_answer.kind_of? Array or new_answer.kind_of? String
+                answer ||= []
+                answer << new_answer
+              when :hash
+                raise Exception, "Hiera type mismatch: expected Hash and got #{new_answer.class}" unless new_answer.kind_of? Hash
+                answer ||= {}
+                answer = new_answer.merge answer
+              else
+                answer = new_answer
+                break
+              end
+            end
           end
         end
 
-        answer = resolve_answer(answer, resolution_type)
-        answer = parse_string(default, scope) if answer.nil?
+        answer = resolve_answer(answer, resolution_type) unless answer.nil?
+        answer = parse_string(default, scope) if answer.nil? and default.is_a?(String)
 
-        return default if answer == empty_answer(resolution_type)
+        return default if answer.nil?
         return answer
       end
     end
diff --git a/lib/hiera/backend/json_backend.rb b/lib/hiera/backend/json_backend.rb
new file mode 100644
index 0000000..3919511
--- /dev/null
+++ b/lib/hiera/backend/json_backend.rb
@@ -0,0 +1,45 @@
+class Hiera
+  module Backend
+    class Json_backend
+      def initialize
+        require 'json'
+
+        Hiera.debug("Hiera JSON backend starting")
+      end
+
+      def lookup(key, scope, order_override, resolution_type)
+        answer = nil
+
+        Hiera.debug("Looking up #{key} in JSON backend")
+
+        Backend.datasources(scope, order_override) do |source|
+          Hiera.debug("Looking for data source #{source}")
+
+          jsonfile = Backend.datafile(:json, scope, source, "json") || next
+
+          data = JSON.parse(File.read(jsonfile))
+
+          next if data.empty?
+          next unless data.include?(key)
+
+          # for array resolution we just append to the array whatever
+          # we find, we then goes onto the next file and keep adding to
+          # the array
+          #
+          # for priority searches we break after the first found data item
+          new_answer = Backend.parse_answer(data[key], scope)
+          case resolution_type
+          when :array
+            answer ||= []
+            answer << new_answer
+          else
+            answer = Backend.parse_answer(data[key], scope)
+            break
+          end
+        end
+
+        return answer
+      end
+    end
+  end
+end
diff --git a/lib/hiera/backend/yaml_backend.rb b/lib/hiera/backend/yaml_backend.rb
index bad83c2..06a9d1e 100644
--- a/lib/hiera/backend/yaml_backend.rb
+++ b/lib/hiera/backend/yaml_backend.rb
@@ -9,7 +9,7 @@ class Hiera
       end
 
       def lookup(key, scope, order_override, resolution_type)
-        answer = Backend.empty_answer(resolution_type)
+        answer = nil
 
         Hiera.debug("Looking up #{key} in YAML backend")
 
@@ -31,6 +31,13 @@ class Hiera
           next if ! @data[yamlfile]
           next if @data[yamlfile].empty?
           next unless @data[yamlfile].include?(key)
+
+          # Extra logging that we found the key. This can be outputted
+          # multiple times if the resolution type is array or hash but that
+          # should be expected as the logging will then tell the user ALL the
+          # places where the key is found.
+          Hiera.debug("Found #{key} in #{source}")
+
           # for array resolution we just append to the array whatever
           # we find, we then goes onto the next file and keep adding to
           # the array
@@ -40,9 +47,11 @@ class Hiera
           case resolution_type
           when :array
             raise Exception, "Hiera type mismatch: expected Array and got #{new_answer.class}" unless new_answer.kind_of? Array or new_answer.kind_of? String
+            answer ||= []
             answer << new_answer
           when :hash
             raise Exception, "Hiera type mismatch: expected Hash and got #{new_answer.class}" unless new_answer.kind_of? Hash
+            answer ||= {}
             answer = new_answer.merge answer
           else
             answer = new_answer
diff --git a/lib/hiera/config.rb b/lib/hiera/config.rb
index 51aa56f..807ed59 100644
--- a/lib/hiera/config.rb
+++ b/lib/hiera/config.rb
@@ -1,17 +1,30 @@
 class Hiera::Config
   class << self
-    # Takes a string or hash as input, strings are treated as filenames
+    ##
+    # load takes a string or hash as input, strings are treated as filenames
     # hashes are stored as data that would have been in the config file
     #
     # Unless specified it will only use YAML as backend with a single
     # 'common' hierarchy and console logger
+    #
+    # @return [Hash] representing the configuration.  e.g.
+    #   {:backends => "yaml", :hierarchy => "common"}
     def load(source)
       @config = {:backends => "yaml",
                  :hierarchy => "common"}
 
       if source.is_a?(String)
         if File.exist?(source)
-          config = YAML.load_file(source)
+          config = begin
+                     yaml_load_file(source)
+                   rescue TypeError => detail
+                     case detail.message
+                     when /no implicit conversion from nil to integer/
+                       false
+                     else
+                       raise detail
+                     end
+                   end
           @config.merge! config if config
         else
           raise "Config file #{source} not found"
@@ -32,6 +45,16 @@ class Hiera::Config
       @config
     end
 
+    ##
+    # yaml_load_file directly delegates to YAML.load_file and is intended to be
+    # a private, internal method suitable for stubbing and mocking.
+    #
+    # @return [Object] return value of {YAML.load_file}
+    def yaml_load_file(source)
+      YAML.load_file(source)
+    end
+    private :yaml_load_file
+
     def load_backends
       @config[:backends].each do |backend|
         begin
diff --git a/lib/hiera/util.rb b/lib/hiera/util.rb
new file mode 100644
index 0000000..be09a11
--- /dev/null
+++ b/lib/hiera/util.rb
@@ -0,0 +1,47 @@
+class Hiera
+  module Util
+    module_function
+
+    def posix?
+      require 'etc'
+      Etc.getpwuid(0) != nil
+    end
+
+    def microsoft_windows?
+      return false unless file_alt_separator
+      
+      begin
+        require 'win32/dir'
+        true
+      rescue LoadError => err
+        warn "Cannot run on Microsoft Windows without the win32-dir gem: #{err}"
+        false
+      end
+    end
+
+    def config_dir
+      if microsoft_windows?
+         File.join(common_appdata, 'PuppetLabs', 'hiera', 'etc')
+      else
+        '/etc'
+      end
+    end
+
+    def var_dir
+      if microsoft_windows?
+        File.join(common_appdata, 'PuppetLabs', 'hiera', 'var')
+      else
+        '/var/lib/hiera'
+      end
+    end
+
+    def file_alt_separator
+      File::ALT_SEPARATOR
+    end
+
+    def common_appdata
+      Dir::COMMON_APPDATA
+    end
+  end
+end
+
diff --git a/metadata.yml b/metadata.yml
deleted file mode 100644
index 1fa2057..0000000
--- a/metadata.yml
+++ /dev/null
@@ -1,70 +0,0 @@
---- !ruby/object:Gem::Specification
-name: hiera
-version: !ruby/object:Gem::Version
-  version: 1.0.0rc3
-  prerelease: 5
-platform: ruby
-authors:
-- Puppet Labs
-autorequire: 
-bindir: bin
-cert_chain: []
-date: 2012-06-19 00:00:00.000000000 Z
-dependencies: []
-description: A pluggable data store for hierarcical data
-email: info at puppetlabs.com
-executables:
-- hiera
-extensions: []
-extra_rdoc_files: []
-files:
-- bin/hiera
-- lib/hiera/console_logger.rb
-- lib/hiera/noop_logger.rb
-- lib/hiera/backend.rb
-- lib/hiera/backend/yaml_backend.rb
-- lib/hiera/config.rb
-- lib/hiera/puppet_logger.rb
-- lib/hiera.rb
-- CHANGELOG
-- COPYING
-- README.md
-- spec/unit/backend_spec.rb
-- spec/unit/console_logger_spec.rb
-- spec/unit/config_spec.rb
-- spec/unit/backend/yaml_backend_spec.rb
-- spec/unit/hiera_spec.rb
-- spec/spec_helper.rb
-- spec/spec.opts
-homepage: https://github.com/puppetlabs/hiera/
-licenses: []
-post_install_message: 
-rdoc_options: []
-require_paths:
-- lib
-required_ruby_version: !ruby/object:Gem::Requirement
-  none: false
-  requirements:
-  - - ! '>='
-    - !ruby/object:Gem::Version
-      version: '0'
-required_rubygems_version: !ruby/object:Gem::Requirement
-  none: false
-  requirements:
-  - - ! '>'
-    - !ruby/object:Gem::Version
-      version: 1.3.1
-requirements: []
-rubyforge_project: 
-rubygems_version: 1.8.23
-signing_key: 
-specification_version: 3
-summary: Light weight hierarcical data store
-test_files:
-- spec/unit/backend_spec.rb
-- spec/unit/console_logger_spec.rb
-- spec/unit/config_spec.rb
-- spec/unit/backend/yaml_backend_spec.rb
-- spec/unit/hiera_spec.rb
-- spec/spec_helper.rb
-- spec/spec.opts
diff --git a/spec/spec.opts b/spec/spec.opts
deleted file mode 100644
index 42d03ee..0000000
--- a/spec/spec.opts
+++ /dev/null
@@ -1 +0,0 @@
---format s --colour --backtrace
diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb
index 33893d5..daf7e75 100644
--- a/spec/spec_helper.rb
+++ b/spec/spec_helper.rb
@@ -2,9 +2,9 @@ $:.insert(0, File.join([File.dirname(__FILE__), "..", "lib"]))
 
 require 'rubygems'
 require 'rspec'
-require 'hiera'
-require 'rspec/mocks'
 require 'mocha'
+require 'hiera'
+require 'tmpdir'
 
 RSpec.configure do |config|
   config.mock_with :mocha
diff --git a/spec/unit/backend/json_backend_spec.rb b/spec/unit/backend/json_backend_spec.rb
new file mode 100644
index 0000000..76e486c
--- /dev/null
+++ b/spec/unit/backend/json_backend_spec.rb
@@ -0,0 +1,89 @@
+require 'spec_helper'
+require 'hiera/backend/json_backend'
+
+class Hiera
+  module Backend
+    describe Json_backend do
+      before do
+        Hiera.stubs(:debug)
+        Hiera.stubs(:warn)
+        Hiera::Backend.stubs(:empty_answer).returns(nil)
+        @backend = Json_backend.new
+      end
+
+      describe "#initialize" do
+        it "should announce its creation" do # because other specs checks this
+          Hiera.expects(:debug).with("Hiera JSON backend starting")
+          Json_backend.new
+        end
+      end
+
+      describe "#lookup" do
+        it "should look for data in all sources" do
+          Backend.expects(:datasources).multiple_yields(["one"], ["two"])
+          Backend.expects(:datafile).with(:json, {}, "one", "json").returns(nil)
+          Backend.expects(:datafile).with(:json, {}, "two", "json").returns(nil)
+
+          @backend.lookup("key", {}, nil, :priority)
+        end
+
+        it "should retain the data types found in data files" do
+          Backend.expects(:datasources).yields("one").times(3)
+          Backend.expects(:datafile).with(:json, {}, "one", "json").returns("/nonexisting/one.json").times(3)
+          File.expects(:read).with("/nonexisting/one.json").returns('{"stringval":"string",
+                                                                      "boolval":true,
+                                                                      "numericval":1}').times(3)
+
+          Backend.stubs(:parse_answer).with('string', {}).returns('string')
+          Backend.stubs(:parse_answer).with(true, {}).returns(true)
+          Backend.stubs(:parse_answer).with(1, {}).returns(1)
+
+          @backend.lookup("stringval", {}, nil, :priority).should == "string"
+          @backend.lookup("boolval", {}, nil, :priority).should == true
+          @backend.lookup("numericval", {}, nil, :priority).should == 1
+        end
+
+        it "should pick data earliest source that has it for priority searches" do
+          scope = {"rspec" => "test"}
+          Backend.stubs(:parse_answer).with('answer', scope).returns("answer")
+          Backend.stubs(:parse_answer).with('test_%{rspec}', scope).returns("test_test")
+          Backend.expects(:datasources).multiple_yields(["one"], ["two"])
+          Backend.expects(:datafile).with(:json, scope, "one", "json").returns("/nonexisting/one.json")
+          Backend.expects(:datafile).with(:json, scope, "two", "json").returns(nil).never
+          File.expects(:read).with("/nonexisting/one.json").returns("one.json")
+          JSON.expects(:parse).with("one.json").returns({"key" => "test_%{rspec}"})
+
+          @backend.lookup("key", scope, nil, :priority).should == "test_test"
+        end
+
+        it "should build an array of all data sources for array searches" do
+          Hiera::Backend.stubs(:empty_answer).returns([])
+          Backend.stubs(:parse_answer).with('answer', {}).returns("answer")
+          Backend.expects(:datafile).with(:json, {}, "one", "json").returns("/nonexisting/one.json")
+          Backend.expects(:datafile).with(:json, {}, "two", "json").returns("/nonexisting/two.json")
+
+          Backend.expects(:datasources).multiple_yields(["one"], ["two"])
+
+          File.expects(:read).with("/nonexisting/one.json").returns("one.json")
+          File.expects(:read).with("/nonexisting/two.json").returns("two.json")
+
+          JSON.expects(:parse).with("one.json").returns({"key" => "answer"})
+          JSON.expects(:parse).with("two.json").returns({"key" => "answer"})
+
+          @backend.lookup("key", {}, nil, :array).should == ["answer", "answer"]
+        end
+
+        it "should parse the answer for scope variables" do
+          Backend.stubs(:parse_answer).with('test_%{rspec}', {'rspec' => 'test'}).returns("test_test")
+          Backend.expects(:datasources).yields("one")
+          Backend.expects(:datafile).with(:json, {"rspec" => "test"}, "one", "json").returns("/nonexisting/one.json")
+
+          File.expects(:read).with("/nonexisting/one.json").returns("one.json")
+          JSON.expects(:parse).with("one.json").returns({"key" => "test_%{rspec}"})
+
+          @backend.lookup("key", {"rspec" => "test"}, nil, :priority).should == "test_test"
+        end
+      end
+    end
+  end
+end
diff --git a/spec/unit/backend/yaml_backend_spec.rb b/spec/unit/backend/yaml_backend_spec.rb
index a897e8a..2f0608d 100644
--- a/spec/unit/backend/yaml_backend_spec.rb
+++ b/spec/unit/backend/yaml_backend_spec.rb
@@ -1,8 +1,5 @@
-require 'tmpdir'
-require 'hiera/backend/yaml_backend'
-require 'hiera/backend'
-require 'fileutils'
 require 'spec_helper'
+require 'hiera/backend/yaml_backend'
 
 class Hiera
   module Backend
@@ -66,15 +63,6 @@ class Hiera
           @backend.lookup("key", {}, nil, :array).should == ["answer", "answer"]
         end
 
-        it "should return empty hash of data sources for hash searches" do
-          Backend.expects(:datasources).multiple_yields(["one"])
-          Backend.expects(:datafile).with(:yaml, {}, "one", "yaml").returns("/nonexisting/one.yaml")
-
-          YAML.expects(:load_file).with("/nonexisting/one.yaml").returns(YAML.load(""))
-
-          @backend.lookup("key", {}, nil, :hash).should == {}
-        end
-
         it "should ignore empty hash of data sources for hash searches" do
           Backend.expects(:datasources).multiple_yields(["one"], ["two"])
           Backend.expects(:datafile).with(:yaml, {}, "one", "yaml").returns("/nonexisting/one.yaml")
diff --git a/spec/unit/backend_spec.rb b/spec/unit/backend_spec.rb
index 85d1239..2a55497 100644
--- a/spec/unit/backend_spec.rb
+++ b/spec/unit/backend_spec.rb
@@ -1,4 +1,5 @@
 require 'spec_helper'
+require 'hiera/util'
 
 class Hiera
   describe Backend do
@@ -9,27 +10,13 @@ class Hiera
         Backend.datadir(:rspec, {})
       end
 
-      it "should default to /var/lib/hiera" do
+      it "should use a default var directory" do
         Config.load({})
-        Backend.expects(:parse_string).with("/var/lib/hiera", {})
+        Backend.expects(:parse_string).with(Hiera::Util.var_dir, {})
         Backend.datadir(:rspec, {})
       end
     end
 
-    describe "#empty_anwer" do
-      it "should return [] for array searches" do
-        Backend.empty_answer(:array).should == []
-      end
-
-      it "should return {} for hash searches" do
-        Backend.empty_answer(:hash).should == {}
-      end
-
-      it "should return nil otherwise" do
-        Backend.empty_answer(:meh).should == nil
-      end
-    end
-
     describe "#datafile" do
       it "should check if the file exist and return nil if not" do
         Hiera.expects(:debug).with("Cannot find datafile /nonexisting/test.yaml, skipping")
@@ -140,6 +127,10 @@ class Hiera
         Backend.parse_string(input, {"rspec" => :undefined}, {"rspec" => "test"}).should == "test_test_test"
       end
 
+      it "should match data in puppet ${::fact} style" do
+        input = "test_%{::rspec}_test"
+        Backend.parse_string(input, {"rspec" => "test"}).should == "test_test_test"
+      end
     end
 
     describe "#parse_answer" do
@@ -238,12 +229,70 @@ class Hiera
         Config.load({})
         Config.instance_variable_set("@config", {:backends => ["yaml", "rspec"]})
         Backend.instance_variable_set("@backends", {"rspec" => backend})
-        Backend::Yaml_backend.any_instance.expects(:lookup).with("key", {"rspec" => "test"}, nil, nil)
+        #Backend::Yaml_backend.any_instance.expects(:lookup).with("key", {"rspec" => "test"}, nil, nil)
         Backend.expects(:constants).returns(["Yaml_backend", "Rspec_backend"]).twice
 
         Backend.lookup("key", "test_%{rspec}", {"rspec" => "test"}, nil, nil).should == "answer"
       end
 
+      it "should call to all backends till an answer is found when doing array lookups" do
+        backend = mock
+        backend.expects(:lookup).returns(["answer"])
+        Config.load({})
+        Config.instance_variable_set("@config", {:backends => ["yaml", "rspec"]})
+        Backend.instance_variable_set("@backends", {"rspec" => backend})
+        Backend.expects(:constants).returns(["Yaml_backend", "Rspec_backend"]).twice
+
+        Backend.lookup("key", "notfound", {"rspec" => "test"}, nil, :array).should == ["answer"]
+      end
+
+      it "should call to all backends till an answer is found when doing hash lookups" do
+        thehash = {:answer => "value"}
+        backend = mock
+        backend.expects(:lookup).returns(thehash)
+        Config.load({})
+        Config.instance_variable_set("@config", {:backends => ["yaml", "rspec"]})
+        Backend.instance_variable_set("@backends", {"rspec" => backend})
+        Backend.expects(:constants).returns(["Yaml_backend", "Rspec_backend"]).twice
+
+        Backend.lookup("key", "notfound", {"rspec" => "test"}, nil, :hash).should == thehash
+      end
+
+      it "should build a merged hash from all backends for hash searches" do
+        backend1 = mock :lookup => {"a" => "answer"}
+        backend2 = mock :lookup => {"b" => "bnswer"}
+        Config.load({})
+        Config.instance_variable_set("@config", {:backends => ["first", "second"]})
+        Backend.instance_variable_set("@backends", {"first" => backend1, "second" => backend2})
+        Backend.stubs(:constants).returns(["First_backend", "Second_backend"])
+
+        Backend.lookup("key", {}, {"rspec" => "test"}, nil, :hash).should == {"a" => "answer", "b" => "bnswer"}
+      end
+
+      it "should build an array from all backends for array searches" do
+        backend1 = mock :lookup => ["a", "b"]
+        backend2 = mock :lookup => ["c", "d"]
+        Config.load({})
+        Config.instance_variable_set("@config", {:backends => ["first", "second"]})
+        Backend.instance_variable_set("@backends", {"first" => backend1, "second" => backend2})
+        Backend.stubs(:constants).returns(["First_backend", "Second_backend"])
+
+        Backend.lookup("key", {}, {"rspec" => "test"}, nil, :array).should == ["a", "b", "c", "d"]
+      end
+
+      it "should use the earliest backend result for priority searches" do
+        backend1 = mock
+        backend1.stubs(:lookup).returns(["a", "b"])
+        backend2 = mock
+        backend2.stubs(:lookup).returns(["c", "d"])
+        Config.load({})
+        Config.instance_variable_set("@config", {:backends => ["first", "second"]})
+        Backend.instance_variable_set("@backends", {"first" => backend1, "second" => backend2})
+        Backend.stubs(:constants).returns(["First_backend", "Second_backend"])
+
+        Backend.lookup("key", {}, {"rspec" => "test"}, nil, :priority).should == ["a", "b"]
+      end
+
       it "should parse the answers based on resolution_type" do
         Config.load({:yaml => {:datadir => "/tmp"}})
         Config.load_backends
diff --git a/spec/unit/config_spec.rb b/spec/unit/config_spec.rb
index 95862bc..60a1627 100644
--- a/spec/unit/config_spec.rb
+++ b/spec/unit/config_spec.rb
@@ -12,14 +12,14 @@ class Hiera
       end
 
       it "should treat string sources as a filename" do
-        expect { Config.load("/nonexisting") }.should raise_error
+        expect { Config.load("/nonexisting") }.to raise_error
       end
 
       it "should raise an error for missing config files" do
         File.expects(:exist?).with("/nonexisting").returns(false)
         YAML.expects(:load_file).with("/nonexisting").never
 
-        expect { Config.load("/nonexisting") }.should raise_error "Config file /nonexisting not found"
+        expect { Config.load("/nonexisting") }.to raise_error "Config file /nonexisting not found"
       end
 
       it "should attempt to YAML load config files" do
@@ -59,6 +59,18 @@ class Hiera
         Hiera.expects(:logger=).with("console")
         Config.load({})
       end
+
+      context "loading '/dev/null' as spec tests do" do
+        before :each do
+          # Simulate the behavior of YAML.load_file('/dev/null') in MRI 1.9.3p194
+          Config.stubs(:yaml_load_file).
+            raises(TypeError, "no implicit conversion from nil to integer")
+        end
+
+        it "is not exceptional behavior" do
+          expect { Config.load('/dev/null') }.to_not raise_error
+        end
+      end
     end
 
     describe "#load_backends" do
diff --git a/spec/unit/hiera_spec.rb b/spec/unit/hiera_spec.rb
index 86c5992..e9edaef 100644
--- a/spec/unit/hiera_spec.rb
+++ b/spec/unit/hiera_spec.rb
@@ -1,4 +1,5 @@
 require 'spec_helper'
+require 'hiera/util'
 
 describe "Hiera" do
   describe "#logger=" do
@@ -30,8 +31,9 @@ describe "Hiera" do
   end
 
   describe "#initialize" do
-    it "should default to /etc/hiera.yaml for config" do
-      Hiera::Config.expects(:load).with("/etc/hiera.yaml")
+    it "should use a default config" do
+      config_file = File.join(Hiera::Util.config_dir, 'hiera.yaml')
+      Hiera::Config.expects(:load).with(config_file)
       Hiera::Config.stubs(:load_backends)
       Hiera.new
     end
diff --git a/spec/unit/util_spec.rb b/spec/unit/util_spec.rb
new file mode 100644
index 0000000..a79eb51
--- /dev/null
+++ b/spec/unit/util_spec.rb
@@ -0,0 +1,49 @@
+require 'spec_helper'
+
+describe Hiera::Util do
+  describe 'Hiera::Util.posix?' do
+    it 'should return true on posix systems' do
+      Etc.expects(:getpwuid).with(0).returns(true)
+      Hiera::Util.posix?.should be_true
+    end
+
+    it 'should return false on non posix systems' do
+      Etc.expects(:getpwuid).with(0).returns(nil)
+      Hiera::Util.posix?.should be_false
+    end
+  end
+
+  describe 'Hiera::Util.microsoft_windows?' do
+    it 'should return false on posix systems' do
+      Hiera::Util.expects(:file_alt_separator).returns(nil)
+      Hiera::Util.microsoft_windows?.should be_false
+    end
+  end
+
+  describe 'Hiera::Util.config_dir' do
+    it 'should return the correct path for posix systems' do
+      Hiera::Util.expects(:file_alt_separator).returns(nil)
+      Hiera::Util.config_dir.should == '/etc'
+    end
+
+    it 'should return the correct path for microsoft windows systems' do
+      Hiera::Util.expects(:microsoft_windows?).returns(true)
+      Hiera::Util.expects(:common_appdata).returns('C:\\ProgramData')
+      Hiera::Util.config_dir.should == 'C:\\ProgramData/PuppetLabs/hiera/etc'
+    end
+  end
+
+  describe 'Hiera::Util.var_dir' do
+    it 'should return the correct path for posix systems' do
+      Hiera::Util.expects(:file_alt_separator).returns(nil)
+      Hiera::Util.var_dir.should == '/var/lib/hiera'
+    end
+
+    it 'should return the correct path for microsoft windows systems' do
+      Hiera::Util.expects(:microsoft_windows?).returns(true)
+      Hiera::Util.expects(:common_appdata).returns('C:\\ProgramData')
+      Hiera::Util.var_dir.should == 'C:\\ProgramData/PuppetLabs/hiera/var'
+    end
+  end
+end
+

-- 
ruby-hiera.git



More information about the Pkg-ruby-extras-commits mailing list