Merge pull request #174 from dprince/file_line_after

Update file_line resource to support 'after'.
This commit is contained in:
Adrien Thebo 2013-09-09 11:17:16 -07:00
commit f4db73672e
3 changed files with 168 additions and 75 deletions

View file

@ -1,5 +1,4 @@
Puppet::Type.type(:file_line).provide(:ruby) do Puppet::Type.type(:file_line).provide(:ruby) do
def exists? def exists?
lines.find do |line| lines.find do |line|
line.chomp == resource[:line].chomp line.chomp == resource[:line].chomp
@ -8,9 +7,11 @@ Puppet::Type.type(:file_line).provide(:ruby) do
def create def create
if resource[:match] if resource[:match]
handle_create_with_match() handle_create_with_match
elsif resource[:after]
handle_create_with_after
else else
handle_create_without_match() append_line
end end
end end
@ -48,11 +49,35 @@ Puppet::Type.type(:file_line).provide(:ruby) do
end end
end end
def handle_create_without_match def handle_create_with_after
regex = Regexp.new(resource[:after])
count = lines.count {|l| l.match(regex)}
case count
when 1 # find the line to put our line after
File.open(resource[:path], 'w') do |fh|
lines.each do |l|
fh.puts(l)
if regex.match(l) then
fh.puts(resource[:line])
end
end
end
when 0 # append the line to the end of the file
append_line
else
raise Puppet::Error, "#{count} lines match pattern '#{resource[:after]}' in file '#{resource[:path]}'. One or no line must match the pattern."
end
end
##
# append the line to the file.
#
# @api private
def append_line
File.open(resource[:path], 'a') do |fh| File.open(resource[:path], 'a') do |fh|
fh.puts resource[:line] fh.puts resource[:line]
end end
end end
end end

View file

@ -42,6 +42,10 @@ Puppet::Type.newtype(:file_line) do
newvalues(true, false) newvalues(true, false)
end end
newparam(:after) do
desc 'An optional value used to specify the line after which we will add any new lines. (Existing lines are added in place)'
end
newparam(:line) do newparam(:line) do
desc 'The line to be appended to the file located by the path parameter.' desc 'The line to be appended to the file located by the path parameter.'
end end

View file

@ -3,33 +3,36 @@ require 'tempfile'
provider_class = Puppet::Type.type(:file_line).provider(:ruby) provider_class = Puppet::Type.type(:file_line).provider(:ruby)
describe provider_class do describe provider_class do
context "when adding" do context "when adding" do
before :each do let :tmpfile do
# TODO: these should be ported over to use the PuppetLabs spec_helper
# file fixtures once the following pull request has been merged:
# https://github.com/puppetlabs/puppetlabs-stdlib/pull/73/files
tmp = Tempfile.new('tmp') tmp = Tempfile.new('tmp')
@tmpfile = tmp.path path = tmp.path
tmp.close! tmp.close!
@resource = Puppet::Type::File_line.new( path
{:name => 'foo', :path => @tmpfile, :line => 'foo'}
)
@provider = provider_class.new(@resource)
end end
let :resource do
Puppet::Type::File_line.new(
{:name => 'foo', :path => tmpfile, :line => 'foo'}
)
end
let :provider do
provider_class.new(resource)
end
it 'should detect if the line exists in the file' do it 'should detect if the line exists in the file' do
File.open(@tmpfile, 'w') do |fh| File.open(tmpfile, 'w') do |fh|
fh.write('foo') fh.write('foo')
end end
@provider.exists?.should be_true provider.exists?.should be_true
end end
it 'should detect if the line does not exist in the file' do it 'should detect if the line does not exist in the file' do
File.open(@tmpfile, 'w') do |fh| File.open(tmpfile, 'w') do |fh|
fh.write('foo1') fh.write('foo1')
end end
@provider.exists?.should be_nil provider.exists?.should be_nil
end end
it 'should append to an existing file when creating' do it 'should append to an existing file when creating' do
@provider.create provider.create
File.read(@tmpfile).chomp.should == 'foo' File.read(tmpfile).chomp.should == 'foo'
end end
end end
@ -52,71 +55,132 @@ describe provider_class do
@provider = provider_class.new(@resource) @provider = provider_class.new(@resource)
end end
it 'should raise an error if more than one line matches, and should not have modified the file' do describe 'using match' do
File.open(@tmpfile, 'w') do |fh| it 'should raise an error if more than one line matches, and should not have modified the file' do
fh.write("foo1\nfoo=blah\nfoo2\nfoo=baz") File.open(@tmpfile, 'w') do |fh|
fh.write("foo1\nfoo=blah\nfoo2\nfoo=baz")
end
@provider.exists?.should be_nil
expect { @provider.create }.to raise_error(Puppet::Error, /More than one line.*matches/)
File.read(@tmpfile).should eql("foo1\nfoo=blah\nfoo2\nfoo=baz")
end end
@provider.exists?.should be_nil
expect { @provider.create }.to raise_error(Puppet::Error, /More than one line.*matches/)
File.read(@tmpfile).should eql("foo1\nfoo=blah\nfoo2\nfoo=baz")
end
it 'should replace all lines that matches' do it 'should replace all lines that matches' do
@resource = Puppet::Type::File_line.new(
{
:name => 'foo',
:path => @tmpfile,
:line => 'foo = bar',
:match => '^foo\s*=.*$',
:multiple => true
}
)
@provider = provider_class.new(@resource)
File.open(@tmpfile, 'w') do |fh|
fh.write("foo1\nfoo=blah\nfoo2\nfoo=baz")
end
@provider.exists?.should be_nil
@provider.create
File.read(@tmpfile).chomp.should eql("foo1\nfoo = bar\nfoo2\nfoo = bar")
end
it 'should raise an error with invalid values' do
expect {
@resource = Puppet::Type::File_line.new( @resource = Puppet::Type::File_line.new(
{ {
:name => 'foo', :name => 'foo',
:path => @tmpfile, :path => @tmpfile,
:line => 'foo = bar', :line => 'foo = bar',
:match => '^foo\s*=.*$', :match => '^foo\s*=.*$',
:multiple => 'asgadga' :multiple => true
} }
) )
}.to raise_error(Puppet::Error, /Invalid value "asgadga"\. Valid values are true, false\./) @provider = provider_class.new(@resource)
File.open(@tmpfile, 'w') do |fh|
fh.write("foo1\nfoo=blah\nfoo2\nfoo=baz")
end
@provider.exists?.should be_nil
@provider.create
File.read(@tmpfile).chomp.should eql("foo1\nfoo = bar\nfoo2\nfoo = bar")
end
it 'should raise an error with invalid values' do
expect {
@resource = Puppet::Type::File_line.new(
{
:name => 'foo',
:path => @tmpfile,
:line => 'foo = bar',
:match => '^foo\s*=.*$',
:multiple => 'asgadga'
}
)
}.to raise_error(Puppet::Error, /Invalid value "asgadga"\. Valid values are true, false\./)
end
it 'should replace a line that matches' do
File.open(@tmpfile, 'w') do |fh|
fh.write("foo1\nfoo=blah\nfoo2")
end
@provider.exists?.should be_nil
@provider.create
File.read(@tmpfile).chomp.should eql("foo1\nfoo = bar\nfoo2")
end
it 'should add a new line if no lines match' do
File.open(@tmpfile, 'w') do |fh|
fh.write("foo1\nfoo2")
end
@provider.exists?.should be_nil
@provider.create
File.read(@tmpfile).should eql("foo1\nfoo2\nfoo = bar\n")
end
it 'should do nothing if the exact line already exists' do
File.open(@tmpfile, 'w') do |fh|
fh.write("foo1\nfoo = bar\nfoo2")
end
@provider.exists?.should be_true
@provider.create
File.read(@tmpfile).chomp.should eql("foo1\nfoo = bar\nfoo2")
end
end end
it 'should replace a line that matches' do describe 'using after' do
File.open(@tmpfile, 'w') do |fh| let :resource do
fh.write("foo1\nfoo=blah\nfoo2") Puppet::Type::File_line.new(
{
:name => 'foo',
:path => @tmpfile,
:line => 'inserted = line',
:after => '^foo1',
}
)
end end
@provider.exists?.should be_nil
@provider.create let :provider do
File.read(@tmpfile).chomp.should eql("foo1\nfoo = bar\nfoo2") provider_class.new(resource)
end
it 'should add a new line if no lines match' do
File.open(@tmpfile, 'w') do |fh|
fh.write("foo1\nfoo2")
end end
@provider.exists?.should be_nil
@provider.create context 'with one line matching the after expression' do
File.read(@tmpfile).should eql("foo1\nfoo2\nfoo = bar\n") before :each do
end File.open(@tmpfile, 'w') do |fh|
it 'should do nothing if the exact line already exists' do fh.write("foo1\nfoo = blah\nfoo2\nfoo = baz")
File.open(@tmpfile, 'w') do |fh| end
fh.write("foo1\nfoo = bar\nfoo2") end
it 'inserts the specified line after the line matching the "after" expression' do
provider.create
File.read(@tmpfile).chomp.should eql("foo1\ninserted = line\nfoo = blah\nfoo2\nfoo = baz")
end
end
context 'with two lines matching the after expression' do
before :each do
File.open(@tmpfile, 'w') do |fh|
fh.write("foo1\nfoo = blah\nfoo2\nfoo1\nfoo = baz")
end
end
it 'errors out stating "One or no line must match the pattern"' do
expect { provider.create }.to raise_error(Puppet::Error, /One or no line must match the pattern/)
end
end
context 'with no lines matching the after expression' do
let :content do
"foo3\nfoo = blah\nfoo2\nfoo = baz\n"
end
before :each do
File.open(@tmpfile, 'w') do |fh|
fh.write(content)
end
end
it 'appends the specified line to the file' do
provider.create
File.read(@tmpfile).should eq(content << resource[:line] << "\n")
end
end end
@provider.exists?.should be_true
@provider.create
File.read(@tmpfile).chomp.should eql("foo1\nfoo = bar\nfoo2")
end end
end end