There's a constant flood of Chef::Util::FileEdit question in stack overflow:
The message is not reaching our community that this API is a tirefire and needs to be replaced with better approaches, and we need to get a bit more aggressive about it.
For users, reading this issue, there's simpler ways to do things directly using the file resource with the content property:
file "/etc/whatever.conf" do
content IO.read("/etc/whatever.conf").gsub(/^STUFF=/, "STUFF=things")
end
Which is a properly convergent resource that does all the right things that we've built into the file resource over the past decade and which we will never build into FileEdit.
There is also the line cookbook:
We should probably bring a resource into core to do this.
https://github.com/poise/poise-file was a prototype for trying to figure out how to work this into the Chef DSL. I think we probably need a bunch more replacement modes, but it's maybe a good starting point?
one thing that i fundamentally don't like about the line cookbook is that each operation is a resource so that if you want to do 100 edits to a given file (kinda gross, but maybe its just looping over an array with append_if_no_such_line) then you'll get 100 resources. really that should be one resource with 100 composable things to it.
i've also considered that this should just be baked directly into the file resource, which would make it available to any inherited resource.
file "/etc/whatever.conf" do
line_edit do
append_if_no_such_line "STUFF=THINGS"
delete_lines_matching /OMGNO/
end
end
Which would mean that you could apply it to a remote_file without the user having to worry about mucking about with downloading and hacking up the file manually.
And lots more useful primitives than the line cookbook, along with supporting raw ruby.
right now though i'm concerned that the line cookbook itself needs a pile of help so i'm cleaning that up and seeing what they're doing there, because i don't like how that is implemented right now
http://augeas.net/ is also a thing we could support
prior art: https://docs.cfengine.com/docs/archive.bak/cf2-Reference.html#editfiles
note that i would generally not consider the functionality provided by the imperative "current-position pointer" cfengine functions -- the "declarative" functions like append_if_no_such_line, append_if_no_line_matching, etc are more where i'm thinking this should go. at some point chef just has ruby which is a full programming language so we don't need to reinvent a new language to edit files, just use ruby.
historical note: https://tickets.opscode.com/browse/CHEF-3290
I tried the technique Lamont suggested i.e.
file "/etc/whatever.conf" do
content IO.read("/etc/whatever.conf").gsub(/^STUFF=/, "STUFF=things")
end
It didn't do what I expected, and I realized:
file "/etc/whatever.conf" do
content lazy { IO.read("/etc/whatever.conf").gsub(/^STUFF=/, "STUFF=things") }
end
would be a safer suggestion. In my case another resource in the run had modified the file before my resource ran, and I was getting the version from before that edit because IO.read ran at compile time. The principle of least surprise would have the resource use the current contents at the time the resource runs as the content to edit.
Most helpful comment
one thing that i fundamentally don't like about the line cookbook is that each operation is a resource so that if you want to do 100 edits to a given file (kinda gross, but maybe its just looping over an array with append_if_no_such_line) then you'll get 100 resources. really that should be one resource with 100 composable things to it.
i've also considered that this should just be baked directly into the file resource, which would make it available to any inherited resource.
Which would mean that you could apply it to a remote_file without the user having to worry about mucking about with downloading and hacking up the file manually.
And lots more useful primitives than the line cookbook, along with supporting raw ruby.