Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

(PUP-5824) Support empty interpolation in Hiera data provider #4637

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
28 changes: 16 additions & 12 deletions lib/puppet/data_providers/hiera_interpolate.rb
Original file line number Diff line number Diff line change
Expand Up @@ -8,21 +8,25 @@ def interpolate(subject, lookup_invocation, allow_methods)
return subject unless subject.is_a?(String) && !subject.index('%{').nil?

lookup_invocation.with(:interpolate, subject) do
subject.gsub(/%\{([^\}]+)\}/) do |match|
method_key, key = get_method_and_data($1, allow_methods)
is_alias = method_key == 'alias'
subject.gsub(/%\{([^\}]*)\}/) do |match|
expr = $1
# Leading and trailing spaces inside an interpolation expression are insignificant
expr.strip!
unless expr.empty? || expr == '::'
method_key, key = get_method_and_data(expr, allow_methods)
is_alias = method_key == 'alias'

# Alias is only permitted if the entire string is equal to the interpolate expression
raise Puppet::DataBinding::LookupError, "'alias' interpolation is only permitted if the expression is equal to the entire string" if is_alias && subject != match
# Alias is only permitted if the entire string is equal to the interpolate expression
raise Puppet::DataBinding::LookupError, "'alias' interpolation is only permitted if the expression is equal to the entire string" if is_alias && subject != match

segments = key.split('.')
value = interpolate_method(method_key).call(segments[0], lookup_invocation)
value = qualified_lookup(segments.drop(1), value) if segments.size > 1
value = lookup_invocation.check(key) { interpolate(value, lookup_invocation, allow_methods) } if value.is_a?(String)

# break gsub and return value immediately if this was an alias substitution. The value might be something other than a String
return value if is_alias
segments = key.split('.')
value = interpolate_method(method_key).call(segments[0], lookup_invocation)
value = qualified_lookup(segments.drop(1), value) if segments.size > 1
value = lookup_invocation.check(key) { interpolate(value, lookup_invocation, allow_methods) } if value.is_a?(String)

# break gsub and return value immediately if this was an alias substitution. The value might be something other than a String
return value if is_alias
end
value || ''
end
end
Expand Down
48 changes: 48 additions & 0 deletions spec/unit/data_providers/hiera_interpolation_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
#! /usr/bin/env ruby
require 'spec_helper'
require 'puppet'
require 'puppet/data_providers/hiera_config'
require 'puppet/data_providers/hiera_interpolate'

describe "Puppet::DataProviders::HieraInterpolate" do

context "when there are empty interpolations %{} in data" do

let(:scope) { {} }
let(:lookup_invocation) {
Puppet::Pops::Lookup::Invocation.new(
scope, {}, {}, nil)
}
let(:interpolator) { Class.new { include Puppet::DataProviders::HieraInterpolate }.new }
let(:empty_interpolation) {'clown%{}shoe'}
let(:empty_interpolation_as_escape) {'clown%%{}{shoe}s'}
let(:only_empty_interpolation) {'%{}'}
let(:empty_namespace) {'%{::}'}
let(:whitespace1) {'%{ :: }'}
let(:whitespace2) {'%{ }'}

it 'should should produce an empty string for the interpolation' do
expect(interpolator.interpolate(empty_interpolation, lookup_invocation, true)).to eq('clownshoe')
end

it 'the empty interpolation can be used as an escape mechanism' do
expect(interpolator.interpolate(empty_interpolation_as_escape, lookup_invocation, true)).to eq('clown%{shoe}s')
end

it 'the value can consist of only an empty escape' do
expect(interpolator.interpolate(only_empty_interpolation, lookup_invocation, true)).to eq('')
end

it 'the value can consist of an empty namespace %{::}' do
expect(interpolator.interpolate(empty_namespace, lookup_invocation, true)).to eq('')
end

it 'the value can consist of whitespace %{ :: }' do
expect(interpolator.interpolate(whitespace1, lookup_invocation, true)).to eq('')
end

it 'the value can consist of whitespace %{ }' do
expect(interpolator.interpolate(whitespace2, lookup_invocation, true)).to eq('')
end
end
end