From: Michael Knox <[email protected]>

Utilising Augeas's SAVE_NEWFILE mode (similar to augtool -n) to
determine the changes that will be made be made by Augeas.
Output a unified diff to info

handle non-default root, and multiple files correctly

Adding tests for Augeas diff functionality
Add test for non-default :root when diff'ing
Ensure that multiple files are diffed if changed, not just one

Signed-off-by: Mike Knox <[email protected]>
---
Local-branch: feature/master/2728
 lib/puppet/provider/augeas/augeas.rb     |   54 +++++++++++++----
 spec/unit/provider/augeas/augeas_spec.rb |   97 ++++++++++++++++++++++++++++++
 2 files changed, 139 insertions(+), 12 deletions(-)

diff --git a/lib/puppet/provider/augeas/augeas.rb 
b/lib/puppet/provider/augeas/augeas.rb
index a16f54b..643462e 100644
--- a/lib/puppet/provider/augeas/augeas.rb
+++ b/lib/puppet/provider/augeas/augeas.rb
@@ -15,9 +15,12 @@
 
 require 'augeas' if Puppet.features.augeas?
 require 'strscan'
+require 'puppet/util'
+require 'puppet/util/diff'
 
 Puppet::Type.type(:augeas).provide(:augeas) do
   include Puppet::Util
+  include Puppet::Util::Diff
 
   confine :true => Puppet.features.augeas?
 
@@ -25,6 +28,8 @@ Puppet::Type.type(:augeas).provide(:augeas) do
 
   SAVE_NOOP = "noop"
   SAVE_OVERWRITE = "overwrite"
+  SAVE_NEWFILE = "newfile"
+  SAVE_BACKUP = "backup"
 
   COMMANDS = {
     "set" => [ :path, :string ],
@@ -287,20 +292,33 @@ Puppet::Type.type(:augeas).provide(:augeas) do
         # actually do the save.
         if return_value and get_augeas_version >= "0.3.6"
           debug("Will attempt to save and only run if files changed")
-          set_augeas_save_mode(SAVE_NOOP)
+          set_augeas_save_mode(SAVE_NEWFILE)
           do_execute_changes
           save_result = @aug.save
           saved_files = @aug.match("/augeas/events/saved")
-          if save_result and not files_changed?
-            debug("Skipping because no files were changed")
-            return_value = false
-          else
+          if save_result and files_changed?
+            root = resource[:root].sub(/^\/$/, "")
+            saved_files.each do |key|
+              saved_file = @aug.get(key).to_s.sub(/^\/files/, root)
+              if Puppet[:show_diff]
+                print diff(saved_file, saved_file + ".augnew")
+              end
+              if Puppet[:noop]
+                File.delete(saved_file + ".augnew")
+              end
+            end
             debug("Files changed, should execute")
+            return_value = true
+          else
+            debug("Skipping because no files were changed or save failed")
+            return_value = false
           end
         end
       end
     ensure
-      close_augeas
+      if not return_value or Puppet[:noop]
+        close_augeas
+      end
     end
     return_value
   end
@@ -309,12 +327,24 @@ Puppet::Type.type(:augeas).provide(:augeas) do
     # Re-connect to augeas, and re-execute the changes
     begin
       open_augeas
-      set_augeas_save_mode(SAVE_OVERWRITE) if get_augeas_version >= "0.3.6"
-
-      do_execute_changes
-
-      success = @aug.save
-      fail("Save failed with return code #{success}") if success != true
+      saved_files = @aug.match("/augeas/events/saved")
+      if saved_files 
+        saved_files.each do |key|
+          root = resource[:root].sub(/^\/$/, "")
+          saved_file = @aug.get(key).to_s.sub(/^\/files/, root)
+          if File.exists?(saved_file + ".augnew")
+            success = File.rename(saved_file + ".augnew", saved_file)
+            debug(saved_file + ".augnew moved to " + saved_file)
+            fail("Rename failed with return code #{success}") if success != 0
+          end
+        end
+      else
+        debug("No saved files, re-executing augeas")
+        set_augeas_save_mode(SAVE_OVERWRITE) if get_augeas_version >= "0.3.6"
+        do_execute_changes
+        success = @aug.save
+        fail("Save failed with return code #{success}") if success != true
+      end
     ensure
       close_augeas
     end
diff --git a/spec/unit/provider/augeas/augeas_spec.rb 
b/spec/unit/provider/augeas/augeas_spec.rb
index 5bb98ea..aeeb196 100755
--- a/spec/unit/provider/augeas/augeas_spec.rb
+++ b/spec/unit/provider/augeas/augeas_spec.rb
@@ -249,6 +249,10 @@ describe provider_class do
   end
 
   describe "need to run" do
+    before do
+      File.stubs(:delete)
+    end
+
     it "should handle no filters" do
       resource = stub("resource")
       resource.stubs(:[]).returns(false).then.returns("").then.returns("")
@@ -339,6 +343,98 @@ describe provider_class do
       provider.stubs(:get_augeas_version).returns("0.3.5")
       provider.need_to_run?.should == false
     end
+
+    # Ticket 2728 (diff files)
+    describe "and Puppet[:show_diff] is set" do
+      before do
+        Puppet[:show_diff] = true
+      end
+
+      it "should call diff when a file is shown to have been changed" do
+        file = "/etc/hosts"
+
+        resource = stub("resource")
+        resource.stubs(:[]).returns(false).then.returns("set /files/foo 
bar").then.returns("")
+        provider = provider_class.new(resource)
+        augeas_stub = stub("augeas")
+        augeas_stub.expects("set").with("/augeas/save", "newfile")
+        augeas_stub.expects("save").returns(true)
+        
augeas_stub.expects("get").with("/augeas/events/saved").returns(["/files#{file}"])
+        
augeas_stub.stubs("match").with("/augeas/events/saved").returns(["/augeas/events/saved"])
+        augeas_stub.stubs("close")
+
+        provider.aug= augeas_stub
+        provider.stubs(:get_augeas_version).returns("0.7.2")
+        provider.expects(:diff).with("#{file}", "#{file}.augnew")
+        provider.need_to_run?.should == true
+      end
+
+      it "should call diff for each file thats changed" do
+        file1 = "/etc/hosts"
+        file2 = "/etc/resolv.conf"
+
+        resource = stub("resource")
+        resource.stubs(:[]).returns(false).then.returns(["set /files/foo bar", 
"set /files/bar foo"]).then.returns("")
+        provider = provider_class.new(resource)
+        augeas_stub = stub("augeas")
+        augeas_stub.expects("set").with("/augeas/save", "newfile")
+        augeas_stub.expects("save").returns(true)
+        
augeas_stub.expects("get").with("/augeas/events/saved[1]").returns(["/files#{file1}"])
+        
augeas_stub.expects("get").with("/augeas/events/saved[2]").returns(["/files#{file2}"])
+        
augeas_stub.stubs("match").with("/augeas/events/saved").returns(["/augeas/events/saved[1]",
 "/augeas/events/saved[2]"])
+        augeas_stub.stubs("close")
+
+        provider.aug= augeas_stub
+        provider.stubs(:get_augeas_version).returns("0.7.2")
+        provider.expects(:diff).with("#{file1}", "#{file1}.augnew")
+        provider.expects(:diff).with("#{file2}", "#{file2}.augnew")
+        provider.need_to_run?.should == true
+      end
+
+      describe "and resource[:root] is set" do
+       before do
+       end
+
+        it "should call diff when a file is shown to have been changed" do
+          root = "/tmp/foo"
+          file = "/etc/hosts"
+
+          resource = stub("resource")
+          resource.stubs(:root).returns("#{root}")
+          resource.stubs(:[]).returns(false).then.returns("set /files/foo 
bar").then.returns("")
+          provider = provider_class.new(resource)
+          augeas_stub = stub("augeas")
+          augeas_stub.expects("set").with("/augeas/save", "newfile")
+          augeas_stub.expects("save").returns(true)
+          
augeas_stub.expects("get").with("/augeas/events/saved").returns(["/files#{root}#{file}"])
+          
augeas_stub.stubs("match").with("/augeas/events/saved").returns(["/augeas/events/saved"])
+          augeas_stub.stubs("close")
+ 
+          provider.aug= augeas_stub
+          provider.stubs(:get_augeas_version).returns("0.7.2")
+          provider.expects(:diff).with("#{root}#{file}", 
"#{root}#{file}.augnew")
+          provider.need_to_run?.should == true
+        end
+      end
+    end
+
+    it "should not call diff if no files change" do
+      file = "/etc/hosts"
+
+      resource = stub("resource")
+      resource.stubs(:[]).returns(false).then.returns("set /files/foo 
bar").then.returns("")
+      provider = provider_class.new(resource)
+      augeas_stub = stub("augeas")
+      augeas_stub.expects("set").with("/augeas/save", "newfile")
+      augeas_stub.expects("save").returns(true)
+      augeas_stub.stubs("match").with("/augeas/events/saved").returns([])
+      augeas_stub.stubs("close")
+
+      provider.aug= augeas_stub
+      provider.stubs(:get_augeas_version).returns("0.7.2")
+      provider.expects(:diff).never
+      provider.need_to_run?.should == false
+    end
   end
 
   describe "augeas execution integration" do
@@ -349,6 +445,7 @@ describe provider_class do
       @augeas = stub("augeas")
       @provider.aug= @augeas
       @provider.stubs(:get_augeas_version).returns("0.3.5")
+      @augeas.stubs(:match).with("/augeas/events/saved")
     end
 
     it "should handle set commands" do
-- 
1.7.3.4

-- 
You received this message because you are subscribed to the Google Groups 
"Puppet Developers" group.
To post to this group, send email to [email protected].
To unsubscribe from this group, send email to 
[email protected].
For more options, visit this group at 
http://groups.google.com/group/puppet-dev?hl=en.

Reply via email to