<?xml version="1.0" encoding="UTF-8"?>
<commit>
  <added type="array">
    <added>
      <filename>chef-server-slice/app/controllers/cookbook_segment.rb</filename>
    </added>
    <added>
      <filename>chef/distro/debian/etc/init.d/chef-client</filename>
    </added>
    <added>
      <filename>chef/distro/debian/etc/init.d/chef-indexer</filename>
    </added>
    <added>
      <filename>chef/distro/debian/etc/init.d/chef-server</filename>
    </added>
    <added>
      <filename>chef/distro/debian/man/man1/chef-indexer.1</filename>
    </added>
    <added>
      <filename>chef/distro/debian/man/man1/chef-server.1</filename>
    </added>
    <added>
      <filename>chef/distro/debian/man/man8/chef-client.8</filename>
    </added>
    <added>
      <filename>chef/distro/debian/man/man8/chef-solo.8</filename>
    </added>
    <added>
      <filename>chef/distro/redhat/etc/chef/client.rb</filename>
    </added>
    <added>
      <filename>chef/distro/redhat/etc/chef/indexer.rb</filename>
    </added>
    <added>
      <filename>chef/distro/redhat/etc/chef/server.rb</filename>
    </added>
    <added>
      <filename>chef/distro/redhat/etc/init.d/chef-client</filename>
    </added>
    <added>
      <filename>chef/distro/redhat/etc/init.d/chef-indexer</filename>
    </added>
    <added>
      <filename>chef/distro/redhat/etc/init.d/chef-server</filename>
    </added>
    <added>
      <filename>chef/lib/chef/mixin/convert_to_class_name.rb</filename>
    </added>
    <added>
      <filename>chef/lib/chef/mixin/recipe_definition_dsl_core.rb</filename>
    </added>
    <added>
      <filename>chef/lib/chef/provider/deploy.rb</filename>
    </added>
    <added>
      <filename>chef/lib/chef/provider/deploy/revision.rb</filename>
    </added>
    <added>
      <filename>chef/lib/chef/provider/deploy/timestamped.rb</filename>
    </added>
    <added>
      <filename>chef/lib/chef/provider/git.rb</filename>
    </added>
    <added>
      <filename>chef/lib/chef/provider/group/gpasswd.rb</filename>
    </added>
    <added>
      <filename>chef/lib/chef/provider/group/usermod.rb</filename>
    </added>
    <added>
      <filename>chef/lib/chef/provider/subversion.rb</filename>
    </added>
    <added>
      <filename>chef/lib/chef/resource/deploy.rb</filename>
    </added>
    <added>
      <filename>chef/lib/chef/resource/deploy_revision.rb</filename>
    </added>
    <added>
      <filename>chef/lib/chef/resource/git.rb</filename>
    </added>
    <added>
      <filename>chef/lib/chef/resource/scm.rb</filename>
    </added>
    <added>
      <filename>chef/lib/chef/resource/subversion.rb</filename>
    </added>
    <added>
      <filename>chef/lib/chef/resource/timestamped_deploy.rb</filename>
    </added>
    <added>
      <filename>chef/spec/data/lwrp/providers/buck_passer.rb</filename>
    </added>
    <added>
      <filename>chef/spec/data/lwrp/providers/buck_passer_2.rb</filename>
    </added>
    <added>
      <filename>chef/spec/data/lwrp/providers/embedded_resource_accesses_providers_scope.rb</filename>
    </added>
    <added>
      <filename>chef/spec/data/lwrp/providers/monkey_name_printer.rb</filename>
    </added>
    <added>
      <filename>chef/spec/data/lwrp/providers/paint_drying_watcher.rb</filename>
    </added>
    <added>
      <filename>chef/spec/data/lwrp/providers/thumb_twiddler.rb</filename>
    </added>
    <added>
      <filename>chef/spec/data/lwrp/resources/bar.rb</filename>
    </added>
    <added>
      <filename>chef/spec/data/lwrp/resources/foo.rb</filename>
    </added>
    <added>
      <filename>chef/spec/unit/lwrp_spec.rb</filename>
    </added>
    <added>
      <filename>chef/spec/unit/mixin/find_preferred_file_spec.rb</filename>
    </added>
    <added>
      <filename>chef/spec/unit/provider/deploy/revision_spec.rb</filename>
    </added>
    <added>
      <filename>chef/spec/unit/provider/deploy/timestamped_spec.rb</filename>
    </added>
    <added>
      <filename>chef/spec/unit/provider/deploy_spec.rb</filename>
    </added>
    <added>
      <filename>chef/spec/unit/provider/git_spec.rb</filename>
    </added>
    <added>
      <filename>chef/spec/unit/provider/group/gpasswd_spec.rb</filename>
    </added>
    <added>
      <filename>chef/spec/unit/provider/group/usermod_spec.rb</filename>
    </added>
    <added>
      <filename>chef/spec/unit/provider/subversion_spec.rb</filename>
    </added>
    <added>
      <filename>chef/spec/unit/resource/deploy_revision_spec.rb</filename>
    </added>
    <added>
      <filename>chef/spec/unit/resource/deploy_spec.rb</filename>
    </added>
    <added>
      <filename>chef/spec/unit/resource/git_spec.rb</filename>
    </added>
    <added>
      <filename>chef/spec/unit/resource/scm_spec.rb</filename>
    </added>
    <added>
      <filename>chef/spec/unit/resource/subversion_spec.rb</filename>
    </added>
    <added>
      <filename>chef/spec/unit/resource/timestamped_deploy_spec.rb</filename>
    </added>
    <added>
      <filename>features/cookbooks/lightweight_resources_and_providers.feature</filename>
    </added>
    <added>
      <filename>features/data/cookbooks/deploy/recipes/callbacks.rb</filename>
    </added>
    <added>
      <filename>features/data/cookbooks/deploy/recipes/default.rb</filename>
    </added>
    <added>
      <filename>features/data/cookbooks/deploy/recipes/embedded_recipe_callbacks.rb</filename>
    </added>
    <added>
      <filename>features/data/cookbooks/deploy/recipes/revision_deploy.rb</filename>
    </added>
    <added>
      <filename>features/data/cookbooks/deploy/recipes/rollback.rb</filename>
    </added>
    <added>
      <filename>features/data/cookbooks/deploy/templates/default/app_config.yml.erb</filename>
    </added>
    <added>
      <filename>features/data/cookbooks/deploy/templates/default/database.yml.erb</filename>
    </added>
    <added>
      <filename>features/data/cookbooks/deploy/templates/default/embedded_recipe_before_symlink.rb.erb</filename>
    </added>
    <added>
      <filename>features/data/cookbooks/deploy/templates/default/sneaky_after_restart_hook.rb.erb</filename>
    </added>
    <added>
      <filename>features/data/cookbooks/deploy/templates/default/sneaky_before_migrate_hook.rb.erb</filename>
    </added>
    <added>
      <filename>features/data/cookbooks/deploy/templates/default/sneaky_before_restart_hook.rb.erb</filename>
    </added>
    <added>
      <filename>features/data/cookbooks/deploy/templates/default/sneaky_before_symlink_hook.rb.erb</filename>
    </added>
    <added>
      <filename>features/data/cookbooks/lwrp/providers/default.rb</filename>
    </added>
    <added>
      <filename>features/data/cookbooks/lwrp/providers/lwp_non_default.rb</filename>
    </added>
    <added>
      <filename>features/data/cookbooks/lwrp/providers/lwp_overridden_load_current_resource.rb</filename>
    </added>
    <added>
      <filename>features/data/cookbooks/lwrp/recipes/default_everything.rb</filename>
    </added>
    <added>
      <filename>features/data/cookbooks/lwrp/recipes/non_default_provider.rb</filename>
    </added>
    <added>
      <filename>features/data/cookbooks/lwrp/recipes/non_default_resource.rb</filename>
    </added>
    <added>
      <filename>features/data/cookbooks/lwrp/recipes/overridden_provider_load_current_resource.rb</filename>
    </added>
    <added>
      <filename>features/data/cookbooks/lwrp/recipes/overridden_resource_initialize.rb</filename>
    </added>
    <added>
      <filename>features/data/cookbooks/lwrp/recipes/provider_invokes_resource.rb</filename>
    </added>
    <added>
      <filename>features/data/cookbooks/lwrp/recipes/provider_is_a_class.rb</filename>
    </added>
    <added>
      <filename>features/data/cookbooks/lwrp/recipes/provider_is_a_string.rb</filename>
    </added>
    <added>
      <filename>features/data/cookbooks/lwrp/recipes/provider_is_a_symbol.rb</filename>
    </added>
    <added>
      <filename>features/data/cookbooks/lwrp/resources/default.rb</filename>
    </added>
    <added>
      <filename>features/data/cookbooks/lwrp/resources/lwr_non_default.rb</filename>
    </added>
    <added>
      <filename>features/data/cookbooks/lwrp/resources/lwr_overridden_initialize.rb</filename>
    </added>
    <added>
      <filename>features/data/cookbooks/scm/metadata.rb</filename>
    </added>
    <added>
      <filename>features/data/cookbooks/scm/recipes/git.rb</filename>
    </added>
    <added>
      <filename>features/data/typo.bundle</filename>
    </added>
    <added>
      <filename>features/provider/deploy/deploy.feature</filename>
    </added>
    <added>
      <filename>features/provider/scm/git.feature</filename>
    </added>
    <added>
      <filename>features/steps/deploy_steps.rb</filename>
    </added>
  </added>
  <modified type="array">
    <modified>
      <diff>@@ -169,7 +169,11 @@ namespace :features do
       t.profile = &quot;recipe_inclusion&quot;
     end
   end
-
+  
+  Cucumber::Rake::Task.new(:lwrp) do |t|
+    t.profile = &quot;lwrp&quot;
+  end
+  
   namespace :provider do
     Cucumber::Rake::Task.new(:template) do |t|
       t.profile = &quot;provider_template&quot;
@@ -179,6 +183,10 @@ namespace :features do
       t.profile = &quot;provider_remote_file&quot;
     end
     
+    Cucumber::Rake::Task.new(:git) do |t|
+      t.profile = &quot;provider_git&quot;
+    end
+    
     namespace :package do
       Cucumber::Rake::Task.new(:macports) do |t|
         t.profile = &quot;provider_package_macports&quot;</diff>
      <filename>Rakefile</filename>
    </modified>
    <modified>
      <diff>@@ -9,7 +9,7 @@ rescue LoadError
 end
 
 GEM_NAME = &quot;chef-server-slice&quot;
-CHEF_SERVER_VERSION=&quot;0.7.11&quot;
+CHEF_SERVER_VERSION=&quot;0.7.12&quot;
 AUTHOR = &quot;Opscode&quot;
 EMAIL = &quot;chef@opscode.com&quot;
 HOMEPAGE = &quot;http://wiki.opscode.com/display/chef&quot;</diff>
      <filename>chef-server-slice/Rakefile</filename>
    </modified>
    <modified>
      <diff>@@ -156,8 +156,12 @@ class ChefServerSlice::Application &lt; Merb::Controller
       files_list = cookbook.definition_files
     when :libraries
       files_list = cookbook.lib_files
+    when :providers
+      files_list = cookbook.provider_files
+    when :resources
+      files_list = cookbook.resource_files
     else
-      raise ArgumentError, &quot;segment must be one of :attributes, :recipes, :definitions or :libraries&quot;
+      raise ArgumentError, &quot;segment must be one of :attributes, :recipes, :definitions, :libraries, :providers, or :resources&quot;
     end
     files_list
   end</diff>
      <filename>chef-server-slice/app/controllers/application.rb</filename>
    </modified>
    <modified>
      <diff>@@ -1,6 +1,7 @@
 #
 # Author:: Adam Jacob (&lt;adam@opscode.com&gt;)
 # Author:: Christopher Brown (&lt;cb@opscode.com&gt;)
+# Author:: Christopher Walters (&lt;cw@opscode.com&gt;)
 # Copyright:: Copyright (c) 2008 Opscode, Inc.
 # License:: Apache License, Version 2.0
 #
@@ -22,7 +23,7 @@ require 'chef' / 'cookbook_loader'
 class ChefServerSlice::Cookbooks &lt; ChefServerSlice::Application
   
   provides :html, :json
-  before :login_required 
+  before :login_required
   
   def index
     @cl = Chef::CookbookLoader.new
@@ -36,28 +37,8 @@ class ChefServerSlice::Cookbooks &lt; ChefServerSlice::Application
     display @cookbook
   end
   
-  def recipe_files
-    node = params.has_key?('node') ? params[:node] : nil 
-    @recipe_files = load_all_files(:recipes, node)
-    display @recipe_files
-  end
-
-  def attribute_files
-    node = params.has_key?('node') ? params[:node] : nil 
-    @attribute_files = load_all_files(:attributes, node)
-    display @attribute_files
-  end
-  
-  def definition_files
-    node = params.has_key?('node') ? params[:node] : nil 
-    @definition_files = load_all_files(:definitions, node)
-    display @definition_files
-  end
-  
-  def library_files
-    node = params.has_key?('node') ? params[:node] : nil 
-    @lib_files = load_all_files(:libraries, node)
-    display @lib_files
+  def files
+    display load_all_files(params[:type], params[:node])
   end
   
 end</diff>
      <filename>chef-server-slice/app/controllers/cookbooks.rb</filename>
    </modified>
    <modified>
      <diff>@@ -31,10 +31,25 @@
               .code
                 %h4.head= link_to File.basename(f), &quot;#&quot;
                 %pre.ruby= syntax_highlight(f)
+        - unless @cookbook.resource_files.empty?
+          %h2.head= link_to &quot;Resource Files&quot;, &quot;#&quot;
+          .files
+            - @cookbook.resource_files.each do |f|
+              .code
+                %h4.head= link_to File.basename(f), &quot;#&quot;
+                %pre.ruby= syntax_highlight(f)
+        - unless @cookbook.provider_files.empty?
+          %h2.head= link_to &quot;Provider Files&quot;, &quot;#&quot;
+          .files
+            - @cookbook.provider_files.each do |f|
+              .code
+                %h4.head= link_to File.basename(f), &quot;#&quot;
+                %pre.ruby= syntax_highlight(f)
         - unless @cookbook.template_files.empty?
           %h2.head= link_to &quot;Template Files&quot;, &quot;#&quot;
           .files
             - @cookbook.template_files.each do |f|
+              - rel = f.split('templates/',2)[1]
               .code
-                %h4.head= link_to File.basename(f), &quot;#&quot;
+                %h4.head= link_to rel, &quot;#&quot;
                 %pre.ruby= syntax_highlight(f)</diff>
      <filename>chef-server-slice/app/views/cookbooks/show.html.haml</filename>
    </modified>
    <modified>
      <diff>@@ -94,16 +94,20 @@ if defined?(Merb::Plugins)
       scope.match(&quot;/search/:search_id/entries/:id&quot;, :method =&gt; 'post').to(:controller =&gt; &quot;search_entries&quot;, :action =&gt; &quot;update&quot;)
       scope.match(&quot;/search/:search_id/entries/:id&quot;, :method =&gt; 'delete').to(:controller =&gt; &quot;search_entries&quot;, :action =&gt; &quot;destroy&quot;)
 
-      scope.match(&quot;/cookbooks/_attribute_files&quot;).to(:controller =&gt; &quot;cookbooks&quot;, :action =&gt; &quot;attribute_files&quot;)
-      scope.match(&quot;/cookbooks/_recipe_files&quot;).to(:controller =&gt; &quot;cookbooks&quot;, :action =&gt; &quot;recipe_files&quot;)
-      scope.match(&quot;/cookbooks/_definition_files&quot;).to(:controller =&gt; &quot;cookbooks&quot;, :action =&gt; &quot;definition_files&quot;)
-      scope.match(&quot;/cookbooks/_library_files&quot;).to(:controller =&gt; &quot;cookbooks&quot;, :action =&gt; &quot;library_files&quot;)
+      scope.match(&quot;/cookbooks/_attribute_files&quot;).to(:controller =&gt; &quot;cookbooks&quot;, :action =&gt; &quot;files&quot;, :type =&gt; :attributes)
+      scope.match(&quot;/cookbooks/_recipe_files&quot;).to(:controller =&gt; &quot;cookbooks&quot;, :action =&gt; &quot;files&quot;, :type =&gt; :recipes)
+      scope.match(&quot;/cookbooks/_definition_files&quot;).to(:controller =&gt; &quot;cookbooks&quot;, :action =&gt; &quot;files&quot;, :type =&gt; :definitions)
+      scope.match(&quot;/cookbooks/_library_files&quot;).to(:controller =&gt; &quot;cookbooks&quot;, :action =&gt; &quot;files&quot;, :type =&gt; :libraries)
+      scope.match(&quot;/cookbooks/_provider_files&quot;).to(:controller =&gt; &quot;cookbooks&quot;, :action =&gt; &quot;files&quot;, :type =&gt; :providers)
+      scope.match(&quot;/cookbooks/_resource_files&quot;).to(:controller =&gt; &quot;cookbooks&quot;, :action =&gt; &quot;files&quot;, :type =&gt; :resources)
 
       scope.match(&quot;/cookbooks/:cookbook_id/templates&quot;, :cookbook_id =&gt; /[\w\.]+/).to(:controller =&gt; &quot;cookbook_templates&quot;, :action =&gt; &quot;index&quot;)
-      scope.match(&quot;/cookbooks/:cookbook_id/libraries&quot;, :cookbook_id =&gt; /[\w\.]+/).to(:controller =&gt; &quot;cookbook_libraries&quot;, :action =&gt; &quot;index&quot;)
-      scope.match(&quot;/cookbooks/:cookbook_id/definitions&quot;, :cookbook_id =&gt; /[\w\.]+/).to(:controller =&gt; &quot;cookbook_definitions&quot;, :action =&gt; &quot;index&quot;)
-      scope.match(&quot;/cookbooks/:cookbook_id/recipes&quot;, :cookbook_id =&gt; /[\w\.]+/).to(:controller =&gt; &quot;cookbook_recipes&quot;, :action =&gt; &quot;index&quot;)
-      scope.match(&quot;/cookbooks/:cookbook_id/attributes&quot;, :cookbook_id =&gt; /[\w\.]+/).to(:controller =&gt; &quot;cookbook_attributes&quot;, :action =&gt; &quot;index&quot;)
+      scope.match(&quot;/cookbooks/:cookbook_id/libraries&quot;, :cookbook_id =&gt; /[\w\.]+/).to(:controller =&gt; &quot;cookbook_segment&quot;, :action =&gt; &quot;index&quot;, :type =&gt; :libraries)
+      scope.match(&quot;/cookbooks/:cookbook_id/definitions&quot;, :cookbook_id =&gt; /[\w\.]+/).to(:controller =&gt; &quot;cookbook_segment&quot;, :action =&gt; &quot;index&quot;, :type =&gt; :definitions)
+      scope.match(&quot;/cookbooks/:cookbook_id/providers&quot;, :cookbook_id =&gt; /[\w\.]+/).to(:controller =&gt; &quot;cookbook_segment&quot;, :action =&gt; &quot;index&quot;, :type =&gt; :providers)
+      scope.match(&quot;/cookbooks/:cookbook_id/resources&quot;, :cookbook_id =&gt; /[\w\.]+/).to(:controller =&gt; &quot;cookbook_segment&quot;, :action =&gt; &quot;index&quot;, :type =&gt; :resources)
+      scope.match(&quot;/cookbooks/:cookbook_id/recipes&quot;, :cookbook_id =&gt; /[\w\.]+/).to(:controller =&gt; &quot;cookbook_segment&quot;, :action =&gt; &quot;index&quot;, :type =&gt; :recipes)
+      scope.match(&quot;/cookbooks/:cookbook_id/attributes&quot;, :cookbook_id =&gt; /[\w\.]+/).to(:controller =&gt; &quot;cookbook_segment&quot;, :action =&gt; &quot;index&quot;, :type =&gt; :attributes)
       scope.match(&quot;/cookbooks/:cookbook_id/files&quot;, :cookbook_id =&gt; /[\w\.]+/).to(:controller =&gt; &quot;cookbook_files&quot;, :action =&gt; &quot;index&quot;)
 
       scope.resources :cookbooks</diff>
      <filename>chef-server-slice/lib/chef-server-slice.rb</filename>
    </modified>
    <modified>
      <filename>chef-server-slice/public/facebox/closelabel.gif</filename>
    </modified>
    <modified>
      <filename>chef-server-slice/public/facebox/loading.gif</filename>
    </modified>
    <modified>
      <filename>chef-server-slice/public/images/treeBuilderImages/Thumbs.db</filename>
    </modified>
    <modified>
      <filename>chef-server-slice/public/images/treeBuilderImages/doc.gif</filename>
    </modified>
    <modified>
      <filename>chef-server-slice/public/images/treeBuilderImages/docNode.gif</filename>
    </modified>
    <modified>
      <filename>chef-server-slice/public/images/treeBuilderImages/docNodeLast.gif</filename>
    </modified>
    <modified>
      <filename>chef-server-slice/public/images/treeBuilderImages/docNodeLastFirst.gif</filename>
    </modified>
    <modified>
      <filename>chef-server-slice/public/images/treeBuilderImages/folder.gif</filename>
    </modified>
    <modified>
      <filename>chef-server-slice/public/images/treeBuilderImages/folderNode.gif</filename>
    </modified>
    <modified>
      <filename>chef-server-slice/public/images/treeBuilderImages/folderNodeFirst.gif</filename>
    </modified>
    <modified>
      <filename>chef-server-slice/public/images/treeBuilderImages/folderNodeLast.gif</filename>
    </modified>
    <modified>
      <filename>chef-server-slice/public/images/treeBuilderImages/folderNodeLastFirst.gif</filename>
    </modified>
    <modified>
      <filename>chef-server-slice/public/images/treeBuilderImages/folderNodeOpen.gif</filename>
    </modified>
    <modified>
      <filename>chef-server-slice/public/images/treeBuilderImages/folderNodeOpenFirst.gif</filename>
    </modified>
    <modified>
      <filename>chef-server-slice/public/images/treeBuilderImages/folderNodeOpenLast.gif</filename>
    </modified>
    <modified>
      <filename>chef-server-slice/public/images/treeBuilderImages/folderNodeOpenLastFirst.gif</filename>
    </modified>
    <modified>
      <filename>chef-server-slice/public/images/treeBuilderImages/folderOpen.gif</filename>
    </modified>
    <modified>
      <filename>chef-server-slice/public/images/treeBuilderImages/vertLine.gif</filename>
    </modified>
    <modified>
      <filename>chef-server-slice/public/javascripts/JSONeditor.js</filename>
    </modified>
    <modified>
      <filename>chef-server-slice/public/javascripts/jquery-1.3.2.min.js</filename>
    </modified>
    <modified>
      <filename>chef-server-slice/public/javascripts/jquery-ui-1.7.1.custom.min.js</filename>
    </modified>
    <modified>
      <filename>chef-server-slice/public/stylesheets/images/ui-bg_diagonals-small_0_aaaaaa_40x40.png</filename>
    </modified>
    <modified>
      <filename>chef-server-slice/public/stylesheets/images/ui-bg_diagonals-thick_15_444444_40x40.png</filename>
    </modified>
    <modified>
      <filename>chef-server-slice/public/stylesheets/images/ui-bg_glass_100_f0f0f0_1x400.png</filename>
    </modified>
    <modified>
      <filename>chef-server-slice/public/stylesheets/images/ui-bg_glass_50_99c2ff_1x400.png</filename>
    </modified>
    <modified>
      <filename>chef-server-slice/public/stylesheets/images/ui-bg_glass_55_fbf5d0_1x400.png</filename>
    </modified>
    <modified>
      <filename>chef-server-slice/public/stylesheets/images/ui-bg_glass_80_e6e6e6_1x400.png</filename>
    </modified>
    <modified>
      <filename>chef-server-slice/public/stylesheets/images/ui-bg_glass_95_fef1ec_1x400.png</filename>
    </modified>
    <modified>
      <filename>chef-server-slice/public/stylesheets/images/ui-bg_highlight-hard_100_f9f9f9_1x100.png</filename>
    </modified>
    <modified>
      <filename>chef-server-slice/public/stylesheets/images/ui-bg_highlight-soft_100_e7eef3_1x100.png</filename>
    </modified>
    <modified>
      <filename>chef-server-slice/public/stylesheets/images/ui-icons_222222_256x240.png</filename>
    </modified>
    <modified>
      <filename>chef-server-slice/public/stylesheets/images/ui-icons_2694e8_256x240.png</filename>
    </modified>
    <modified>
      <filename>chef-server-slice/public/stylesheets/images/ui-icons_2e83ff_256x240.png</filename>
    </modified>
    <modified>
      <filename>chef-server-slice/public/stylesheets/images/ui-icons_72a7cf_256x240.png</filename>
    </modified>
    <modified>
      <filename>chef-server-slice/public/stylesheets/images/ui-icons_888888_256x240.png</filename>
    </modified>
    <modified>
      <filename>chef-server-slice/public/stylesheets/images/ui-icons_cd0a0a_256x240.png</filename>
    </modified>
    <modified>
      <filename>chef-server-slice/public/stylesheets/images/ui-icons_ffffff_256x240.png</filename>
    </modified>
    <modified>
      <filename>chef-server-slice/public/stylesheets/jquery-ui-1.7.1.custom.css</filename>
    </modified>
    <modified>
      <diff>@@ -18,7 +18,7 @@ require 'chef' unless defined?(Chef)
 include FileUtils
 
 GEM = &quot;chef-server&quot;
-CHEF_SERVER_VERSION = &quot;0.7.11&quot;
+CHEF_SERVER_VERSION = &quot;0.7.12&quot;
 AUTHOR = &quot;Opscode&quot;
 EMAIL = &quot;chef@opscode.com&quot;
 HOMEPAGE = &quot;http://wiki.opscode.com/display/chef&quot;</diff>
      <filename>chef-server/Rakefile</filename>
    </modified>
    <modified>
      <diff>@@ -4,7 +4,7 @@ require 'rake/rdoctask'
 require './tasks/rspec.rb'
 
 GEM = &quot;chef&quot;
-CHEF_VERSION = &quot;0.7.11&quot;
+CHEF_VERSION = &quot;0.7.12&quot;
 AUTHOR = &quot;Adam Jacob&quot;
 EMAIL = &quot;adam@opscode.com&quot;
 HOMEPAGE = &quot;http://wiki.opscode.com/display/chef&quot;
@@ -23,14 +23,15 @@ spec = Gem::Specification.new do |s|
   s.homepage = HOMEPAGE
   
   s.add_dependency &quot;mixlib-config&quot;, &quot;&gt;= 1.0.12&quot;
+  s.add_dependency &quot;ohai&quot;, &quot;&gt;= 0.3.4&quot;
   %w{mixlib-cli mixlib-log ruby-openid
     json erubis extlib
-    stomp ohai}.each { |gem| s.add_dependency gem }
+    stomp}.each { |gem| s.add_dependency gem }
   
   s.bindir       = &quot;bin&quot;
   s.executables  = %w( chef-client chef-solo )
   s.require_path = 'lib'
-  s.files = %w(LICENSE README.rdoc) + Dir.glob(&quot;lib/**/*&quot;)
+  s.files = %w(LICENSE README.rdoc) + Dir.glob(&quot;{distro,lib}/**/*&quot;)
 end
 
 Rake::GemPackageTask.new(spec) do |pkg|</diff>
      <filename>chef/Rakefile</filename>
    </modified>
    <modified>
      <diff>@@ -27,7 +27,7 @@ require 'chef/config'
 Dir[File.join(File.dirname(__FILE__), 'chef/mixin/**/*.rb')].sort.each { |lib| require lib }
 
 class Chef
-  VERSION = '0.7.11'
+  VERSION = '0.7.12'
 end
 
 # Adds a Dir.glob to Ruby 1.8.5, for compat</diff>
      <filename>chef/lib/chef.rb</filename>
    </modified>
    <modified>
      <diff>@@ -1,5 +1,6 @@
 #
 # Author:: Adam Jacob (&lt;adam@opscode.com&gt;)
+# Author:: Christopher Walters (&lt;cw@opscode.com&gt;)
 # Copyright:: Copyright (c) 2008 Opscode, Inc.
 # License:: Apache License, Version 2.0
 #
@@ -56,6 +57,10 @@ class Chef
     #  * build_node - Get the last known state, merge with local changes
     #  * register - Make sure we have an openid
     #  * authenticate - Authenticate with our openid
+    #  * sync_library_files - Populate the local cache with all the library files
+    #  * sync_provider_files - Populate the local cache with all the provider files
+    #  * sync_resource_files - Populate the local cache with all the resource files
+    #  * sync_attribute_files - Populate the local cache with all the attribute files
     #  * sync_definitions - Populate the local cache with all the definitions
     #  * sync_recipes - Populate the local cache with all the recipes
     #  * do_attribute_files - Populate the local cache with all attributes, and execute them
@@ -75,6 +80,8 @@ class Chef
       build_node(@node_name)
       save_node
       sync_library_files
+      sync_provider_files
+      sync_resource_files
       sync_attribute_files
       sync_definitions
       sync_recipes
@@ -97,7 +104,7 @@ class Chef
     def run_solo
       start_time = Time.now
       Chef::Log.info(&quot;Starting Chef Solo Run&quot;)
-      
+
       determine_node_name
       build_node(@node_name, true)
       converge(true)
@@ -117,7 +124,7 @@ class Chef
 
     def determine_node_name
       run_ohai
-      unless @safe_name &amp;&amp; @node_name
+      unless safe_name &amp;&amp; node_name
         @node_name ||= @ohai[:fqdn] ? @ohai[:fqdn] : @ohai[:hostname]
         @safe_name = @node_name.gsub(/\./, '_')
       end
@@ -324,7 +331,29 @@ class Chef
       update_file_cache(&quot;libraries&quot;, @rest.get_rest(&quot;cookbooks/_library_files?node=#{@node.name}&quot;))
       true
     end
+
+    # Gets all the provider files included in all the cookbooks available on the server,
+    # and loads them.
+    #
+    # === Returns
+    # true:: Always returns true
+    def sync_provider_files
+      Chef::Log.debug(&quot;Synchronizing providers&quot;) 
+      update_file_cache(&quot;providers&quot;, @rest.get_rest(&quot;cookbooks/_provider_files?node=#{@node.name}&quot;))
+      true
+    end
     
+    # Gets all the resource files included in all the cookbooks available on the server,
+    # and loads them.
+    #
+    # === Returns
+    # true:: Always returns true
+    def sync_resource_files
+      Chef::Log.debug(&quot;Synchronizing resources&quot;)
+      update_file_cache(&quot;resources&quot;, @rest.get_rest(&quot;cookbooks/_resource_files?node=#{@node.name}&quot;))
+      true
+    end
+
     # Gets all the definition files included in all the cookbooks available on the server,
     # and loads them.
     #
@@ -372,13 +401,9 @@ class Chef
         Chef::Config[:cookbook_path] = File.join(Chef::Config[:file_cache_path], &quot;cookbooks&quot;)
       end
       compile = Chef::Compile.new(@node)
-      compile.load_libraries
-      compile.load_attributes
-      compile.load_definitions
-      compile.load_recipes
-
+      
       Chef::Log.debug(&quot;Converging node #{@safe_name}&quot;)
-      cr = Chef::Runner.new(@node, compile.collection)
+      cr = Chef::Runner.new(@node, compile.collection, compile.definitions, compile.cookbook_loader)
       cr.converge
       true
     end</diff>
      <filename>chef/lib/chef/client.rb</filename>
    </modified>
    <modified>
      <diff>@@ -1,5 +1,6 @@
 #
 # Author:: Adam Jacob (&lt;adam@opscode.com&gt;)
+# Author:: Christopher Walters (&lt;cw@opscode.com&gt;)
 # Copyright:: Copyright (c) 2008 Opscode, Inc.
 # License:: Apache License, Version 2.0
 #
@@ -27,8 +28,8 @@ class Chef
       
     attr_accessor :node, :cookbook_loader, :collection, :definitions
     
-    # Creates a new Chef::Compile object.  This object gets used by the Chef Server to generate
-    # a fully compiled recipe list for a node.
+    # Creates a new Chef::Compile object and populates its fields. This object gets
+    # used by the Chef Server to generate a fully compiled recipe list for a node.
     #
     # === Returns
     # object&lt;Chef::Compile&gt;:: Duh. :)
@@ -40,6 +41,13 @@ class Chef
       @recipes = Array.new
       @default_attributes = Array.new
       @override_attributes = Array.new
+
+      load_libraries
+      load_providers
+      load_resources
+      load_attributes
+      load_definitions
+      load_recipes
     end
     
     # Looks up the node via the &quot;name&quot; argument, first from CouchDB, then by calling
@@ -97,6 +105,30 @@ class Chef
       end
       true
     end
+
+    # Load all the providers, from every cookbook, so they are available when we process
+    # the recipes.
+    #
+    # === Returns
+    # true:: Always returns true
+    def load_providers()
+      @cookbook_loader.each do |cookbook|
+        cookbook.load_providers
+      end
+      true
+    end
+
+    # Load all the resources, from every cookbook, so they are available when we process
+    # the recipes.
+    #
+    # === Returns
+    # true:: Always returns true
+    def load_resources()
+      @cookbook_loader.each do |cookbook|
+        cookbook.load_resources
+      end
+      true
+    end
     
     # Load all the recipes specified in the node data (loaded via load_node, above.)
     # </diff>
      <filename>chef/lib/chef/compile.rb</filename>
    </modified>
    <modified>
      <diff>@@ -1,5 +1,6 @@
 #
 # Author:: Adam Jacob (&lt;adam@opscode.com&gt;)
+# Author:: Christopher Walters (&lt;cw@opscode.com&gt;)
 # Copyright:: Copyright (c) 2008 Opscode, Inc.
 # License:: Apache License, Version 2.0
 #
@@ -19,12 +20,14 @@ require 'chef/log'
 require 'chef/node'
 require 'chef/resource_definition'
 require 'chef/recipe'
+require 'chef/mixin/convert_to_class_name'
 
 class Chef
   class Cookbook
+    include Chef::Mixin::ConvertToClassName
     
     attr_accessor :attribute_files, :definition_files, :template_files, :remote_files, 
-                  :lib_files, :name
+                  :lib_files, :resource_files, :provider_files, :name
     attr_reader :recipe_files
     
     # Creates a new Chef::Cookbook object.  
@@ -40,6 +43,8 @@ class Chef
       @recipe_files = Array.new
       @recipe_names = Hash.new
       @lib_files = Array.new
+      @resource_files = Array.new
+      @provider_files = Array.new
     end
     
     # Loads all the library files in this cookbook via require.
@@ -89,6 +94,28 @@ class Chef
       end
       results
     end
+
+    # Loads all the resources in this cookbook.
+    #
+    # === Returns
+    # true:: Always returns true
+    def load_resources
+      @resource_files.each do |file|
+        Chef::Log.debug(&quot;Loading cookbook #{name}'s resources from #{file}&quot;)
+        Chef::Resource.build_from_file(name, file)
+      end
+    end
+    
+    # Loads all the providers in this cookbook.
+    #
+    # === Returns
+    # true:: Always returns true
+    def load_providers
+      @provider_files.each do |file|
+        Chef::Log.debug(&quot;Loading cookbook #{name}'s providers from #{file}&quot;)
+        Chef::Provider.build_from_file(name, file)
+      end
+    end
     
     def recipe_files=(*args)
       @recipe_files = args.flatten
@@ -141,4 +168,4 @@ class Chef
     end
     
   end
-end
\ No newline at end of file
+end</diff>
      <filename>chef/lib/chef/cookbook.rb</filename>
    </modified>
    <modified>
      <diff>@@ -1,6 +1,9 @@
 #
 # Author:: Adam Jacob (&lt;adam@opscode.com&gt;)
+# Author:: Christopher Walters (&lt;cw@opscode.com&gt;)
+# Author:: Daniel DeLeo (&lt;dan@kallistec.com&gt;)
 # Copyright:: Copyright (c) 2008 Opscode, Inc.
+# Copyright:: Copyright (c) 2009 Daniel DeLeo
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the &quot;License&quot;);
@@ -29,74 +32,86 @@ class Chef
     def initialize()
       @cookbook = Hash.new
       @metadata = Hash.new
+      @ignore_regexes = Hash.new { |hsh, key| hsh[key] = Array.new }
       load_cookbooks
     end
     
     def load_cookbooks
       cookbook_settings = Hash.new
-      Chef::Config.cookbook_path.each do |cb_path|
+      [Chef::Config.cookbook_path].flatten.reverse.each do |cb_path|
         Dir[File.join(cb_path, &quot;*&quot;)].each do |cookbook|
           next unless File.directory?(cookbook)          
           cookbook_name = File.basename(cookbook).to_sym
           unless cookbook_settings.has_key?(cookbook_name)
             cookbook_settings[cookbook_name] = { 
-              :ignore_regexes =&gt; Array.new,
-              :attribute_files =&gt; Array.new,
-              :definition_files =&gt; Array.new,
-              :recipe_files =&gt; Array.new,
-              :template_files =&gt; Array.new,
-              :remote_files =&gt; Array.new,
-              :lib_files =&gt; Array.new,
-              :metadata_files =&gt; Array.new
+              :attribute_files  =&gt; Hash.new,
+              :definition_files =&gt; Hash.new,
+              :recipe_files     =&gt; Hash.new,
+              :template_files   =&gt; Hash.new,
+              :remote_files     =&gt; Hash.new,
+              :lib_files        =&gt; Hash.new,
+              :resource_files   =&gt; Hash.new,
+              :provider_files   =&gt; Hash.new,
+              :metadata_files   =&gt; Array.new
             }
           end
           ignore_regexes = load_ignore_file(File.join(cookbook, &quot;ignore&quot;))
-          cookbook_settings[cookbook_name][:ignore_regexes].concat(ignore_regexes)
+          @ignore_regexes[cookbook_name].concat(ignore_regexes)
+          
           load_files_unless_basename(
             File.join(cookbook, &quot;attributes&quot;, &quot;*.rb&quot;), 
-            cookbook_settings[cookbook_name][:attribute_files],
-            cookbook_settings[cookbook_name][:ignore_regexes]
+            cookbook_settings[cookbook_name][:attribute_files]
           )
           load_files_unless_basename(
             File.join(cookbook, &quot;definitions&quot;, &quot;*.rb&quot;), 
-            cookbook_settings[cookbook_name][:definition_files],
-            cookbook_settings[cookbook_name][:ignore_regexes]
+            cookbook_settings[cookbook_name][:definition_files]
           )
           load_files_unless_basename(
             File.join(cookbook, &quot;recipes&quot;, &quot;*.rb&quot;), 
-            cookbook_settings[cookbook_name][:recipe_files],
-            cookbook_settings[cookbook_name][:ignore_regexes]
+            cookbook_settings[cookbook_name][:recipe_files]
           )
           load_files_unless_basename(
             File.join(cookbook, &quot;libraries&quot;, &quot;*.rb&quot;),               
-            cookbook_settings[cookbook_name][:lib_files],
-            cookbook_settings[cookbook_name][:ignore_regexes]
+            cookbook_settings[cookbook_name][:lib_files]
           )
           load_cascading_files(
             &quot;*.erb&quot;,
             File.join(cookbook, &quot;templates&quot;),
-            cookbook_settings[cookbook_name][:template_files],
-            cookbook_settings[cookbook_name][:ignore_regexes]
+            cookbook_settings[cookbook_name][:template_files]
           )
           load_cascading_files(
             &quot;*&quot;,
             File.join(cookbook, &quot;files&quot;),
-            cookbook_settings[cookbook_name][:remote_files],
-            cookbook_settings[cookbook_name][:ignore_regexes]
+            cookbook_settings[cookbook_name][:remote_files]
           )
+          load_cascading_files(
+            &quot;*.rb&quot;,
+            File.join(cookbook, &quot;resources&quot;),
+            cookbook_settings[cookbook_name][:resource_files]
+          )
+          load_cascading_files(
+            &quot;*.rb&quot;,
+            File.join(cookbook, &quot;providers&quot;),
+            cookbook_settings[cookbook_name][:provider_files]
+          )
+
           if File.exists?(File.join(cookbook, &quot;metadata.json&quot;))
             cookbook_settings[cookbook_name][:metadata_files] &lt;&lt; File.join(cookbook, &quot;metadata.json&quot;)
           end
         end
       end
+      remove_ignored_files_from(cookbook_settings)
+      
       cookbook_settings.each_key do |cookbook|
         @cookbook[cookbook] = Chef::Cookbook.new(cookbook)
-        @cookbook[cookbook].attribute_files = cookbook_settings[cookbook][:attribute_files]
-        @cookbook[cookbook].definition_files = cookbook_settings[cookbook][:definition_files]
-        @cookbook[cookbook].recipe_files = cookbook_settings[cookbook][:recipe_files]
-        @cookbook[cookbook].template_files = cookbook_settings[cookbook][:template_files]
-        @cookbook[cookbook].remote_files = cookbook_settings[cookbook][:remote_files]
-        @cookbook[cookbook].lib_files = cookbook_settings[cookbook][:lib_files]
+        @cookbook[cookbook].attribute_files = cookbook_settings[cookbook][:attribute_files].values
+        @cookbook[cookbook].definition_files = cookbook_settings[cookbook][:definition_files].values
+        @cookbook[cookbook].recipe_files = cookbook_settings[cookbook][:recipe_files].values
+        @cookbook[cookbook].template_files = cookbook_settings[cookbook][:template_files].values
+        @cookbook[cookbook].remote_files = cookbook_settings[cookbook][:remote_files].values
+        @cookbook[cookbook].lib_files = cookbook_settings[cookbook][:lib_files].values
+        @cookbook[cookbook].resource_files = cookbook_settings[cookbook][:resource_files].values
+        @cookbook[cookbook].provider_files = cookbook_settings[cookbook][:provider_files].values
         @metadata[cookbook] = Chef::Cookbook::Metadata.new(@cookbook[cookbook])
         cookbook_settings[cookbook][:metadata_files].each do |meta_json|
           @metadata[cookbook].from_json(IO.read(meta_json))
@@ -133,35 +148,32 @@ class Chef
         results
       end
       
-      def load_cascading_files(file_glob, base_path, result_array, ignore_regexes)
-        # To handle dotfiles like .ssh
-        Dir.glob(File.join(base_path, &quot;**/#{file_glob}&quot;), File::FNM_DOTMATCH).each do |file|
-          next if skip_file(file, ignore_regexes)
-          file =~ /^#{base_path}\/(.+)$/
-          singlecopy = $1
-          unless result_array.detect { |f| f =~ /#{singlecopy}$/ }
-            result_array &lt;&lt; file
+      def remove_ignored_files_from(cookbook_settings)
+        file_types_to_inspect = [ :attribute_files, :definition_files, :recipe_files, :template_files, 
+                                  :remote_files, :lib_files, :resource_files, :provider_files]
+        
+        @ignore_regexes.each do |cookbook_name, regexes|
+          regexes.each do |regex|
+            settings = cookbook_settings[cookbook_name]
+            file_types_to_inspect.each do |file_type|
+              settings[file_type].delete_if { |uniqname, fullpath| fullpath.match(regex) }
+            end
           end
         end
       end
       
-      def load_files_unless_basename(file_glob, result_array, ignore_regexes)
-        Dir[file_glob].each do |file|
-          next if skip_file(file, ignore_regexes)
-          file_basename = File.basename(file)
-          # If we've seen a file with this basename before, skip it.
-          unless result_array.detect { |f| File.basename(f) == file_basename }  
-            result_array &lt;&lt; file
-          end
+      def load_cascading_files(file_glob, base_path, result_hash)
+        rm_base_path = /^#{base_path}\/(.+)$/
+        # To handle dotfiles like .ssh
+        Dir.glob(File.join(base_path, &quot;**/#{file_glob}&quot;), File::FNM_DOTMATCH).each do |file|
+          result_hash[rm_base_path.match(file)[1]] = file
         end
       end
       
-      def skip_file(file, ignore_regexes)
-        skip = false
-        ignore_regexes.each do |exp|
-          skip = true if exp.match(file)
+      def load_files_unless_basename(file_glob, result_hash)
+        Dir[file_glob].each do |file|
+          result_hash[File.basename(file)] = file
         end
-        skip
       end
       
   end</diff>
      <filename>chef/lib/chef/cookbook_loader.rb</filename>
    </modified>
    <modified>
      <diff>@@ -112,13 +112,22 @@ class Chef
           end
         end
         
+        status, stdout, stderr = output_of_command(args[:command], args)
+        command_output &lt;&lt; &quot;STDOUT: #{stdout}&quot;
+        command_output &lt;&lt; &quot;STDERR: #{stderr}&quot;
+        handle_command_failures(status, command_output, args)
+        
+        status
+      end
+      
+      module_function :run_command
+      
+      def output_of_command(command, args)
+        Chef::Log.debug(&quot;Executing #{command}&quot;)
+        stderr_string, stdout_string, status = &quot;&quot;, &quot;&quot;, nil
+        
         exec_processing_block = lambda do |pid, stdin, stdout, stderr|
-          Chef::Log.debug(&quot;---- Begin output of #{args[:command]} ----&quot;)
-          Chef::Log.debug(&quot;STDOUT: #{stdout.string.chomp}&quot;)
-          Chef::Log.debug(&quot;STDERR: #{stderr.string.chomp}&quot;)
-          command_output &lt;&lt; &quot;STDOUT: #{stdout.string.chomp}&quot;
-          command_output &lt;&lt; &quot;STDERR: #{stderr.string.chomp}&quot;
-          Chef::Log.debug(&quot;---- End output of #{args[:command]} ----&quot;)
+          stdout_string, stderr_string = stdout.string.chomp, stderr.string.chomp
         end
         
         args[:cwd] ||= Dir.tmpdir        
@@ -126,44 +135,65 @@ class Chef
           raise Chef::Exceptions::Exec, &quot;#{args[:cwd]} does not exist or is not a directory&quot;
         end
         
-        Chef::Log.debug(&quot;Executing #{args[:command]}&quot;)
-        
-        status = nil
-        
         Dir.chdir(args[:cwd]) do
           if args[:timeout]
             begin
               Timeout.timeout(args[:timeout]) do
-                status = popen4(args[:command], args, &amp;exec_processing_block)
+                status = popen4(command, args, &amp;exec_processing_block)
               end
             rescue Timeout::Error =&gt; e
-              Chef::Log.error(&quot;#{args[:command]} exceeded timeout #{args[:timeout]}&quot;)
+              Chef::Log.error(&quot;#{command} exceeded timeout #{args[:timeout]}&quot;)
               raise(e)
             end
           else
-            status = popen4(args[:command], args, &amp;exec_processing_block)
+            status = popen4(command, args, &amp;exec_processing_block)
           end
           
-          unless args[:ignore_failure] 
-            args[:returns] ||= 0
-            if status.exitstatus != args[:returns]
-              # if the log level is not debug, through output of command when we fail
-              output = &quot;&quot;
-              if Chef::Log.logger.level &gt; 0
-                output &lt;&lt; &quot;\n---- Begin output of #{args[:command]} ----\n&quot;
-                output &lt;&lt; &quot;#{command_output}&quot;
-                output &lt;&lt; &quot;---- End output of #{args[:command]} ----\n&quot;
-              end
-              raise Chef::Exceptions::Exec, &quot;#{args[:command]} returned #{status.exitstatus}, expected #{args[:returns]}#{output}&quot;
+          Chef::Log.debug(&quot;---- Begin output of #{command} ----&quot;)
+          Chef::Log.debug(&quot;STDOUT: #{stdout_string}&quot;)
+          Chef::Log.debug(&quot;STDERR: #{stderr_string}&quot;)
+          Chef::Log.debug(&quot;---- End output of #{command} ----&quot;)
+          Chef::Log.debug(&quot;Ran #{command} returned #{status.exitstatus}&quot;)
+        end
+        
+        return status, stdout_string, stderr_string
+      end
+      
+      module_function :output_of_command
+      
+      def handle_command_failures(status, command_output, args={})
+        unless args[:ignore_failure] 
+          args[:returns] ||= 0
+          if status.exitstatus != args[:returns]
+            # if the log level is not debug, through output of command when we fail
+            output = &quot;&quot;
+            if Chef::Log.logger.level &gt; 0
+              output &lt;&lt; &quot;\n---- Begin output of #{args[:command]} ----\n&quot;
+              output &lt;&lt; &quot;#{command_output}&quot;
+              output &lt;&lt; &quot;---- End output of #{args[:command]} ----\n&quot;
             end
+            raise Chef::Exceptions::Exec, &quot;#{args[:command]} returned #{status.exitstatus}, expected #{args[:returns]}#{output}&quot;
           end
-          Chef::Log.debug(&quot;Ran #{args[:command]} returned #{status.exitstatus}&quot;)
         end
-        status
       end
       
-      module_function :run_command
+      module_function :handle_command_failures
            
+      # Call #run_command but set LC_ALL to the system's current environment so it doesn't get changed to C.
+      #
+      # === Parameters
+      # args&lt;Hash&gt;: A number of required and optional arguments that will be handed out to #run_command
+      #
+      # === Returns
+      # Returns the result of #run_command
+      def run_command_with_systems_locale(args={})
+        args[:environment] ||= {}
+        args[:environment][&quot;LC_ALL&quot;] = ENV[&quot;LC_ALL&quot;]
+        run_command args
+      end
+
+      module_function :run_command_with_systems_locale
+
       # This is taken directly from Ara T Howard's Open4 library, and then 
       # modified to suit the needs of Chef.  Any bugs here are most likely
       # my own, and not Ara's.
@@ -189,7 +219,14 @@ class Chef
         unless args[:group].kind_of?(Integer)
           args[:group] = Etc.getgrnam(args[:group]).gid if args[:group]
         end
-        args[:environment] ||= nil
+        args[:environment] ||= {}
+
+        # Default on C locale so parsing commands output can be done
+        # independently of the node's default locale.
+        # &quot;LC_ALL&quot; could be set to nil, in which case we also must ignore it.
+        unless args[:environment].has_key?(&quot;LC_ALL&quot;)
+          args[:environment][&quot;LC_ALL&quot;] = &quot;C&quot;
+        end
         
         pw, pr, pe, ps = IO.pipe, IO.pipe, IO.pipe, IO.pipe
 
@@ -223,10 +260,8 @@ class Chef
               Process.uid = args[:user]
             end
             
-            if args[:environment]
-              args[:environment].each do |key,value|
-                ENV[key] = value
-              end
+            args[:environment].each do |key,value|
+              ENV[key] = value
             end
 
             if args[:umask]</diff>
      <filename>chef/lib/chef/mixin/command.rb</filename>
    </modified>
    <modified>
      <diff>@@ -72,26 +72,17 @@ class Chef
           File.join(&quot;#{platform}&quot;, &quot;#{file_name}&quot;),
           File.join(&quot;default&quot;, &quot;#{file_name}&quot;)
         ]
-        to_send = nil
         
+        file_list_str = file_list.keys.join(&quot;\n&quot;)
         preferences.each do |pref|
           Chef::Log.debug(&quot;Looking for #{pref}&quot;)
-          file_list.each_key do |file|
-            Chef::Log.debug(&quot;Checking for #{pref} #{file} &quot;)
-            if file =~ /#{pref}$/
-              Chef::Log.debug(&quot;Matched #{pref} for #{file}!&quot;)
-              to_send = file
-              break
-            end
+          matcher = /^(.+#{pref})$/
+          if match = matcher.match(file_list_str)
+            return match[1]
           end
-          break if to_send
         end
         
-        unless to_send
-          raise Chef::Exceptions::FileNotFound, &quot;Cannot find a preferred file for #{file_name}!&quot;
-        end
-        
-        to_send
+        raise Chef::Exceptions::FileNotFound, &quot;Cannot find a preferred file for #{file_name}!&quot;
       end
       
     end</diff>
      <filename>chef/lib/chef/mixin/find_preferred_file.rb</filename>
    </modified>
    <modified>
      <diff>@@ -1,5 +1,6 @@
 #
 # Author:: Adam Jacob (&lt;adam@opscode.com&gt;)
+# Author:: Christopher Walters (&lt;cw@opscode.com&gt;)
 # Copyright:: Copyright (c) 2008 Opscode, Inc.
 # License:: Apache License, Version 2.0
 #
@@ -31,6 +32,19 @@ class Chef
           raise IOError, &quot;Cannot open or read #{filename}!&quot;
         end
       end
+
+      # Loads a given ruby file, and runs class_eval against it in the context of the current 
+      # object.
+      #
+      # Raises an IOError if the file cannot be found, or is not readable.
+      def class_from_file(filename)
+        if File.exists?(filename) &amp;&amp; File.readable?(filename)
+          self.class_eval(IO.read(filename), filename, 1)
+        else
+          raise IOError, &quot;Cannot open or read #{filename}!&quot;
+        end
+      end
+
     end
   end
 end</diff>
      <filename>chef/lib/chef/mixin/from_file.rb</filename>
    </modified>
    <modified>
      <diff>@@ -23,6 +23,7 @@ class Chef
     module GenerateURL
     
       def generate_cookbook_url(url, cookbook, type, node, args=nil)
+        Chef::Log.debug(&quot;generating cookbook url for url=#{url}, cookbook=#{cookbook.inspect}, type=#{type}, node=#{node}&quot;)
         new_url = nil
         if url =~ /^(http|https):\/\//
           new_url = url
@@ -39,7 +40,7 @@ class Chef
             end
           end
         end
-
+        Chef::Log.debug(&quot;generated cookbook url: #{new_url}&quot;)
         return new_url
       end
       </diff>
      <filename>chef/lib/chef/mixin/generate_url.rb</filename>
    </modified>
    <modified>
      <diff>@@ -93,7 +93,7 @@ class Chef
         :bash =&gt; Chef::Provider::Script,
         :csh =&gt; Chef::Provider::Script,
         :user =&gt; Chef::Provider::User::Useradd,
-        :group =&gt; Chef::Provider::Group::Groupadd,
+        :group =&gt; Chef::Provider::Group::Gpasswd,
         :http_request =&gt; Chef::Provider::HttpRequest,
         :route =&gt; Chef::Provider::Route,
         :ifconfig =&gt; Chef::Provider::Ifconfig,</diff>
      <filename>chef/lib/chef/platform.rb</filename>
    </modified>
    <modified>
      <diff>@@ -1,6 +1,7 @@
 #
 # Author:: Adam Jacob (&lt;adam@opscode.com&gt;)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
+# Author:: Christopher Walters (&lt;cw@opscode.com&gt;)
+# Copyright:: Copyright (c) 2008, 2009 Opscode, Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the &quot;License&quot;);
@@ -16,15 +17,25 @@
 # limitations under the License.
 #
 
+require 'chef/mixin/from_file'
+require 'chef/mixin/convert_to_class_name'
+require 'chef/mixin/recipe_definition_dsl_core'
+
 class Chef
   class Provider
     
+    include Chef::Mixin::RecipeDefinitionDSLCore
+    
     attr_accessor :node, :new_resource, :current_resource
     
-    def initialize(node, new_resource)
+    def initialize(node, new_resource, collection=nil, definitions={}, cookbook_loader=nil)
       @node = node
       @new_resource = new_resource
       @current_resource = nil
+      @collection = collection
+      @definitions = definitions
+      @cookbook_loader = cookbook_loader
+      @cookbook_name = @new_resource.cookbook_name
     end
     
     def load_current_resource
@@ -36,5 +47,55 @@ class Chef
       true
     end
     
+    protected
+    
+    def recipe_eval(*args, &amp;block)
+      provider_collection, @collection = @collection, Chef::ResourceCollection.new
+      
+      instance_eval(*args, &amp;block)
+      Chef::Runner.new(@node, @collection).converge
+      
+      @collection = provider_collection
+    end
+    
+    public
+    
+    class &lt;&lt; self
+      include Chef::Mixin::ConvertToClassName
+      
+      def build_from_file(cookbook_name, filename)
+        pname = filename_to_qualified_string(cookbook_name, filename)
+        
+        new_provider_class = Class.new self do |cls|
+          
+          def load_current_resource
+            # silence Chef::Exceptions::Override exception
+          end
+          
+          class &lt;&lt; cls
+            include Chef::Mixin::FromFile
+            
+            # setup DSL's shortcut methods
+            def action(name, &amp;block)
+              define_method(&quot;action_#{name.to_s}&quot;) do
+                instance_eval(&amp;block)
+              end
+            end
+          end
+          
+          # load provider definition from file
+          cls.class_from_file(filename)
+        end
+        
+        # register new class as a Chef::Provider
+        pname = filename_to_qualified_string(cookbook_name, filename)
+        class_name = convert_to_class_name(pname)
+        Chef::Provider.const_set(class_name, new_provider_class)
+        Chef::Log.debug(&quot;Loaded contents of #{filename} into a provider named #{pname} defined in Chef::Provider::#{class_name}&quot;)
+        
+        new_provider_class
+      end
+    end
+
   end
 end</diff>
      <filename>chef/lib/chef/provider.rb</filename>
    </modified>
    <modified>
      <diff>@@ -25,8 +25,8 @@ class Chef
     class Cron &lt; Chef::Provider
       include Chef::Mixin::Command
 
-      def initialize(node, new_resource)
-        super(node, new_resource)
+      def initialize(node, new_resource, collection=nil, definitions=nil, cookbook_loader=nil)
+        super(node, new_resource, collection, definitions, cookbook_loader)
         @cron_exists = false
         @cron_empty = false
       end
@@ -35,17 +35,46 @@ class Chef
       def load_current_resource
         crontab = String.new
         @current_resource = Chef::Resource::Cron.new(@new_resource.name)
+        @current_resource.user(@new_resource.user)
         status = popen4(&quot;crontab -l -u #{@new_resource.user}&quot;) do |pid, stdin, stdout, stderr|
           stdout.each { |line| crontab &lt;&lt; line }
         end
         if status.exitstatus &gt; 1
           raise Chef::Exceptions::Cron, &quot;Error determining state of #{@new_resource.name}, exit: #{status.exitstatus}&quot;
         elsif status.exitstatus == 0
+          cron_found = false
           crontab.each do |line|
             case line
             when /^# Chef Name: #{@new_resource.name}/
               Chef::Log.debug(&quot;Found cron '#{@new_resource.name}'&quot;)
+              cron_found = true
               @cron_exists = true
+              next
+            when /^MAILTO=(\S*)/
+              @current_resource.mailto($1) if cron_found
+              next
+            when /^PATH=(\S*)/
+              @current_resource.path($1) if cron_found
+              next
+            when /^SHELL=(\S*)/
+              @current_resource.shell($1) if cron_found
+              next
+            when /^HOME=(\S*)/
+              @current_resource.home($1) if cron_found
+              next
+            when /([0-9\*]+)\s*([0-9\*]+)\s*([0-9\*]+)\s*([0-9\*]+)\s*([0-9\*]+)\s*(.*)/
+              if cron_found
+                @current_resource.minute($1) 
+                @current_resource.hour($2) 
+                @current_resource.day($3)
+                @current_resource.month($4) 
+                @current_resource.weekday($5) 
+                @current_resource.command($6)
+                cron_found=false
+              end
+              next
+            else
+              next
             end
           end
           Chef::Log.debug(&quot;Cron '#{@new_resource.name}' not found&quot;) unless @cron_exists
@@ -57,36 +86,53 @@ class Chef
         @current_resource
       end
 
+      def compare_cron
+        [ :minute, :hour, :day, :month, :weekday, :command, :mailto, :path, :shell, :home ].any? do |cron_var|
+          !@new_resource.send(cron_var).nil? &amp;&amp; @new_resource.send(cron_var) != @current_resource.send(cron_var)
+        end
+      end
+
       def action_create
         crontab = String.new
+        newcron = String.new
         cron_found = false
+
+        newcron &lt;&lt; &quot;# Chef Name: #{new_resource.name}\n&quot;
+        [ :mailto, :path, :shell, :home ].each do |v|
+          newcron &lt;&lt; &quot;#{v.to_s.upcase}=#{@new_resource.send(v)}\n&quot; if @new_resource.send(v)
+        end
+        newcron &lt;&lt; &quot;#{@new_resource.minute} #{@new_resource.hour} #{@new_resource.day} #{@new_resource.month} #{@new_resource.weekday} #{@new_resource.command}\n&quot;
+
         if @cron_exists
+          unless compare_cron
+            Chef::Log.debug(&quot;Skipping existing cron entry '#{@new_resource.name}'&quot;)
+            return
+          end
           status = popen4(&quot;crontab -l -u #{@new_resource.user}&quot;) do |pid, stdin, stdout, stderr|
             stdout.each_line do |line|
-              if cron_found
-                cronline = &quot;#{@new_resource.minute} #{@new_resource.hour} #{@new_resource.day} #{@new_resource.month} #{@new_resource.weekday} #{@new_resource.command}\n&quot;
-                if (line == cronline)
-                  Chef::Log.debug(&quot;Skipping existing cron entry '#{@new_resource.name}'&quot;)
-                  return
-                end
-                crontab &lt;&lt; cronline
-                cron_found = false
-                next
-              end
               case line
-              when /^# Chef Name: #{new_resource.name}\n/
+              when /^# Chef Name: #{@new_resource.name}\n/
                 cron_found = true
+                next
+              when /([0-9\*]+)\s*([0-9\*]+)\s*([0-9\*]+)\s*([0-9\*]+)\s*([0-9\*]+)\s*(.*)/
+                if cron_found
+                  cron_found = false
+                  crontab &lt;&lt; newcron
+                  next
+                end
+              else
+                next if cron_found
               end
               crontab &lt;&lt; line 
             end
           end
 
-
           status = popen4(&quot;crontab -u #{@new_resource.user} -&quot;, :waitlast =&gt; true) do |pid, stdin, stdout, stderr|
             crontab.each { |line| stdin.puts &quot;#{line}&quot; }
             stdin.close
           end
           Chef::Log.info(&quot;Updated cron '#{@new_resource.name}'&quot;)
+          @new_resource.updated = true
         else
           unless @cron_empty
             status = popen4(&quot;crontab -l -u #{@new_resource.user}&quot;) do |pid, stdin, stdout, stderr|
@@ -94,14 +140,14 @@ class Chef
             end
           end
   
-          crontab &lt;&lt; &quot;# Chef Name: #{new_resource.name}\n&quot;
-          crontab &lt;&lt; &quot;#{@new_resource.minute} #{@new_resource.hour} #{@new_resource.day} #{@new_resource.month} #{@new_resource.weekday} #{@new_resource.command}\n&quot;
-  
+          crontab &lt;&lt; newcron
+
           status = popen4(&quot;crontab -u #{@new_resource.user} -&quot;, :waitlast =&gt; true) do |pid, stdin, stdout, stderr|
             crontab.each { |line| stdin.puts &quot;#{line}&quot; }
             stdin.close
           end
           Chef::Log.info(&quot;Added cron '#{@new_resource.name}'&quot;)
+          @new_resource.updated = true
         end
       end
 
@@ -111,14 +157,17 @@ class Chef
           cron_found = false
           status = popen4(&quot;crontab -l -u #{@new_resource.user}&quot;) do |pid, stdin, stdout, stderr|
             stdout.each_line do |line|
-              if cron_found
-                cron_found = false
-                next
-              end
               case line
-              when /^# Chef Name: #{new_resource.name}\n/
+              when /^# Chef Name: #{@new_resource.name}\n/
                 cron_found = true
                 next
+              when /([0-9\*]+)\s*([0-9\*]+)\s*([0-9\*]+)\s*([0-9\*]+)\s*([0-9\*]+)\s*(.*)/
+                if cron_found
+                  cron_found = false
+                  next
+                end
+              else
+                next if cron_found
               end
               crontab &lt;&lt; line 
             end
@@ -129,6 +178,7 @@ class Chef
             stdin.close
           end
           Chef::Log.debug(&quot;Deleted cron '#{@new_resource.name}'&quot;)
+          @new_resource.updated = true
         end
       end
 </diff>
      <filename>chef/lib/chef/provider/cron.rb</filename>
    </modified>
    <modified>
      <diff>@@ -27,8 +27,8 @@ class Chef
       include Chef::Mixin::Command
       attr_accessor :group_exists
       
-      def initialize(node, new_resource)
-        super(node, new_resource)
+      def initialize(node, new_resource, collection=nil, definitions=nil, cookbook_loader=nil)
+        super(node, new_resource, collection, definitions, cookbook_loader)
         @group_exists = true
       end
       </diff>
      <filename>chef/lib/chef/provider/group.rb</filename>
    </modified>
    <modified>
      <diff>@@ -26,8 +26,7 @@ class Chef
           
           [ &quot;/usr/sbin/groupadd&quot;,
             &quot;/usr/sbin/groupmod&quot;,
-            &quot;/usr/sbin/groupdel&quot;,
-            &quot;/usr/bin/gpasswd&quot; ].each do |required_binary|
+            &quot;/usr/sbin/groupdel&quot; ].each do |required_binary|
             raise Chef::Exceptions::Group, &quot;Could not find binary #{required_binary} for #{@new_resource}&quot; unless ::File.exists?(required_binary)
           end
         end
@@ -54,21 +53,8 @@ class Chef
         end
         
         def modify_group_members
-          unless @new_resource.members.empty?
-            if(@new_resource.append)
-              @new_resource.members.each do |member|
-                Chef::Log.debug(&quot;#{@new_resource}: appending member #{member} to group #{@new_resource.group_name}&quot;)
-                run_command(:command =&gt; &quot;gpasswd -a #{member} #{@new_resource.group_name}&quot;)
-              end
-            else
-              Chef::Log.debug(&quot;#{@new_resource}: setting group members to #{@new_resource.members.join(', ')}&quot;)
-              run_command(:command =&gt; &quot;gpasswd -M #{@new_resource.members.join(',')} #{@new_resource.group_name}&quot;)
-            end
-          else
-            Chef::Log.debug(&quot;#{@new_resource}: not changing group members, the group has no members&quot;)
-          end
+          raise Chef::Exceptions::Group, &quot;you must override modify_group_members in #{self.to_s}&quot;
         end
-        
         # Little bit of magic as per Adam's useradd provider to pull the assign the command line flags
         #
         # ==== Returns</diff>
      <filename>chef/lib/chef/provider/group/groupadd.rb</filename>
    </modified>
    <modified>
      <diff>@@ -106,7 +106,7 @@ class Chef
       def generate_config
         b = binding
         case node[:platform]
-        when (&quot;centos&quot; || &quot;redhat&quot; || &quot;fedora&quot;)
+        when &quot;centos&quot;,&quot;redhat&quot;,&quot;fedora&quot;
           content = %{
 &lt;% if @new_resource.device %&gt;DEVICE=&lt;%= @new_resource.device %&gt;&lt;% end %&gt;
 &lt;% if @new_resource.onboot %&gt;ONBOOT=&lt;%= @new_resource.onboot %&gt;&lt;% end %&gt;
@@ -120,9 +120,9 @@ class Chef
           network_file = ::File.new(&quot;/etc/sysconfig/network-scripts/ifcfg-#{@new_resource.device}&quot;, &quot;w&quot;)
           network_file.puts(template.result(b))
           network_file.close
-        when (&quot;debian&quot; || &quot;ubantu&quot;)
+        when &quot;debian&quot;,&quot;ubuntu&quot;
           # template
-        when (&quot;slackware&quot;)
+        when &quot;slackware&quot;
           # template
         end
       end </diff>
      <filename>chef/lib/chef/provider/ifconfig.rb</filename>
    </modified>
    <modified>
      <diff>@@ -26,10 +26,6 @@ class Chef
 
       include Chef::Mixin::Command
 
-      def initialize(node, new_resource)
-        super(node, new_resource)
-      end
-
       def action_mount
         unless @current_resource.mounted
           Chef::Log.debug(&quot;#{@new_resource}: attempting to mount&quot;)</diff>
      <filename>chef/lib/chef/provider/mount.rb</filename>
    </modified>
    <modified>
      <diff>@@ -27,8 +27,8 @@ class Chef
 
         include Chef::Mixin::Command
 
-        def initialize(node, new_resource)
-          super(node, new_resource)
+        def initialize(node, new_resource, collection=nil, definitions=nil, cookbook_loader=nil)
+          super(node, new_resource, collection, definitions, cookbook_loader)
           @real_device = nil
         end
         attr_accessor :real_device</diff>
      <filename>chef/lib/chef/provider/mount/mount.rb</filename>
    </modified>
    <modified>
      <diff>@@ -30,8 +30,8 @@ class Chef
       
       attr_accessor :candidate_version
       
-      def initialize(node, new_resource)
-        super(node, new_resource)
+      def initialize(node, new_resource, collection=nil, definitions=nil, cookbook_loader=nil)
+        super(node, new_resource, collection, definitions, cookbook_loader)
         @candidate_version = nil
       end
       </diff>
      <filename>chef/lib/chef/provider/package.rb</filename>
    </modified>
    <modified>
      <diff>@@ -61,7 +61,7 @@ class Chef
         end
       
         def install_package(name, version)
-          run_command(
+          run_command_with_systems_locale(
             :command =&gt; &quot;apt-get -q -y#{expand_options(@new_resource.options)} install #{name}=#{version}&quot;,
             :environment =&gt; {
               &quot;DEBIAN_FRONTEND&quot; =&gt; &quot;noninteractive&quot;
@@ -74,7 +74,7 @@ class Chef
         end
       
         def remove_package(name, version)
-          run_command(
+          run_command_with_systems_locale(
             :command =&gt; &quot;apt-get -q -y#{expand_options(@new_resource.options)} remove #{@new_resource.package_name}&quot;,
             :environment =&gt; {
               &quot;DEBIAN_FRONTEND&quot; =&gt; &quot;noninteractive&quot;
@@ -83,7 +83,7 @@ class Chef
         end
       
         def purge_package(name, version)
-          run_command(
+          run_command_with_systems_locale(
             :command =&gt; &quot;apt-get -q -y#{expand_options(@new_resource.options)} purge #{@new_resource.package_name}&quot;,
             :environment =&gt; {
               &quot;DEBIAN_FRONTEND&quot; =&gt; &quot;noninteractive&quot;
@@ -95,7 +95,7 @@ class Chef
           preseed_file = get_preseed_file(name, version)
           if preseed_file
             Chef::Log.info(&quot;Pre-seeding #{@new_resource} with package installation instructions.&quot;)
-            run_command(
+            run_command_with_systems_locale(
               :command =&gt; &quot;debconf-set-selections #{preseed_file}&quot;,
               :environment =&gt; {
                 &quot;DEBIAN_FRONTEND&quot; =&gt; &quot;noninteractive&quot;</diff>
      <filename>chef/lib/chef/provider/package/apt.rb</filename>
    </modified>
    <modified>
      <diff>@@ -40,10 +40,9 @@ class Chef
             Chef::Log.debug(&quot;Checking dpkg status for #{@new_resource.package_name}&quot;)
             status = popen4(&quot;dpkg-deb -W #{@new_resource.source}&quot;) do |pid, stdin, stdout, stderr|
               stdout.each do |line|
-                case line
-                when /([\w\d]+)\t([\w\d.-]+)/
-                  @current_resource.package_name($1)
-                  @new_resource.version($2)
+                if pkginfo = /([a-z\d\-\+]+)\t([\w\d.-]+)/.match(line)
+                  @current_resource.package_name(pkginfo[1])
+                  @new_resource.version(pkginfo[2])
                 end
               end
             end
@@ -79,31 +78,28 @@ class Chef
         end
      
         def install_package(name, version)
-          run_command(
+          run_command_with_systems_locale(
             :command =&gt; &quot;dpkg -i#{expand_options(@new_resource.options)} #{@new_resource.source}&quot;,
             :environment =&gt; {
-              &quot;DEBIAN_FRONTEND&quot; =&gt; &quot;noninteractive&quot;,
-              &quot;LANG&quot; =&gt; &quot;en_US&quot;
+              &quot;DEBIAN_FRONTEND&quot; =&gt; &quot;noninteractive&quot;
             }
           )
         end
 
         def remove_package(name, version)
-          run_command(
+          run_command_with_systems_locale(
             :command =&gt; &quot;dpkg -r#{expand_options(@new_resource.options)} #{@new_resource.package_name}&quot;,
             :environment =&gt; {
-              &quot;DEBIAN_FRONTEND&quot; =&gt; &quot;noninteractive&quot;,
-              &quot;LANG&quot; =&gt; &quot;en_US&quot;
+              &quot;DEBIAN_FRONTEND&quot; =&gt; &quot;noninteractive&quot;
             }
           )
         end
       
         def purge_package(name, version)
-          run_command(
+          run_command_with_systems_locale(
             :command =&gt; &quot;dpkg -P#{expand_options(@new_resource.options)} #{@new_resource.package_name}&quot;,
             :environment =&gt; {
-              &quot;DEBIAN_FRONTEND&quot; =&gt; &quot;noninteractive&quot;,
-              &quot;LANG&quot; =&gt; &quot;en_US&quot;
+              &quot;DEBIAN_FRONTEND&quot; =&gt; &quot;noninteractive&quot;
             }
           )
         end</diff>
      <filename>chef/lib/chef/provider/package/dpkg.rb</filename>
    </modified>
    <modified>
      <diff>@@ -110,24 +110,24 @@ class Chef
           unless @current_resource.version
             case @new_resource.source
             when /^ports$/
-              run_command(
+              run_command_with_systems_locale(
                 :command =&gt; &quot;make -DBATCH install&quot;,
                 :cwd =&gt; &quot;#{port_path}&quot;
               )
             when /^http/, /^ftp/
-              run_command(
+              run_command_with_systems_locale(
                 :command =&gt; &quot;pkg_add -r #{package_name}&quot;,
                 :environment =&gt; { &quot;PACKAGESITE&quot; =&gt; @new_resource.source }
               )
               Chef::Log.info(&quot;Installed package #{package_name} from: #{@new_resource.source}&quot;)
             when /^\//
-              run_command(
+              run_command_with_systems_locale(
                 :command =&gt; &quot;pkg_add #{@new_resource.name}&quot;,
                 :environment =&gt; { &quot;PKG_PATH&quot; =&gt; @new_resource.source }
               )
               Chef::Log.info(&quot;Installed package #{@new_resource.name} from: #{@new_resource.source}&quot;)
             else
-              run_command(
+              run_command_with_systems_locale(
                 :command =&gt; &quot;pkg_add -r #{latest_link_name}&quot;
               )
               Chef::Log.info(&quot;Installed package #{package_name}&quot;)
@@ -138,11 +138,11 @@ class Chef
         def remove_package(name, version)
           # a version is mandatory
           if version
-            run_command(
+            run_command_with_systems_locale(
               :command =&gt; &quot;pkg_delete #{package_name}-#{version}&quot;
             )
           else
-            run_command(
+            run_command_with_systems_locale(
               :command =&gt; &quot;pkg_delete #{package_name}-#{@current_resource.version}&quot;
             )
           end</diff>
      <filename>chef/lib/chef/provider/package/freebsd.rb</filename>
    </modified>
    <modified>
      <diff>@@ -45,7 +45,7 @@ class Chef
           unless @current_resource.version == version
             command = &quot;port install #{name}&quot;
             command &lt;&lt; &quot; @#{version}&quot; if version and !version.empty? 
-            run_command(
+            run_command_with_systems_locale(
               :command =&gt; command
             )
           end
@@ -54,7 +54,7 @@ class Chef
         def purge_package(name, version)
           command = &quot;port uninstall #{name}&quot;
           command &lt;&lt; &quot; @#{version}&quot; if version and !version.empty?
-          run_command(
+          run_command_with_systems_locale(
             :command =&gt; command
           )
         end
@@ -63,7 +63,7 @@ class Chef
           command = &quot;port deactivate #{name}&quot;
           command &lt;&lt; &quot; @#{version}&quot; if version and !version.empty?
 
-          run_command(
+          run_command_with_systems_locale(
             :command =&gt; command
           )
         end
@@ -78,7 +78,7 @@ class Chef
             # that hasn't been installed.
             install_package(name, version)
           elsif current_version != version
-            run_command(
+            run_command_with_systems_locale(
               :command =&gt; &quot;port upgrade #{name} @#{version}&quot;
             )
           end</diff>
      <filename>chef/lib/chef/provider/package/macports.rb</filename>
    </modified>
    <modified>
      <diff>@@ -93,7 +93,7 @@ class Chef
             pkg = &quot;~#{name}-#{$1}&quot;
           end
      
-          run_command(
+          run_command_with_systems_locale(
             :command =&gt; &quot;emerge -g --color n --nospinner --quiet#{expand_options(@new_resource.options)} #{pkg}&quot;
           )
         end
@@ -109,7 +109,7 @@ class Chef
             pkg = &quot;#{@new_resource.package_name}&quot;
           end
 
-          run_command(
+          run_command_with_systems_locale(
             :command =&gt; &quot;emerge --unmerge --color n --nospinner --quiet#{expand_options(@new_resource.options)} #{pkg}&quot;
           )
         end</diff>
      <filename>chef/lib/chef/provider/package/portage.rb</filename>
    </modified>
    <modified>
      <diff>@@ -69,24 +69,24 @@ class Chef
         end
         
         def install_package(name, version)
-          run_command(
+          run_command_with_systems_locale(
             :command =&gt; &quot;rpm -i #{@new_resource.source}&quot;
           )
         end
         
         def upgrade_package(name, version)
-          run_command(
+          run_command_with_systems_locale(
             :command =&gt; &quot;rpm -U #{@new_resource.source}&quot;
           )
         end
         
         def remove_package(name, version)
           if version
-            run_command(
+            run_command_with_systems_locale(
               :command =&gt; &quot;rpm -e #{name}-#{version}&quot;
             )
           else
-            run_command(
+            run_command_with_systems_locale(
               :command =&gt; &quot;rpm -e #{name}&quot;
             )
           end</diff>
      <filename>chef/lib/chef/provider/package/rpm.rb</filename>
    </modified>
    <modified>
      <diff>@@ -99,7 +99,7 @@ class Chef
           if @new_resource.source
             src = &quot;  --source=#{@new_resource.source} --source=http://gems.rubyforge.org&quot;
           end  
-          run_command(
+          run_command_with_systems_locale(
             :command =&gt; &quot;#{gem_binary_path} install #{name} -q --no-rdoc --no-ri -v \&quot;#{version}\&quot;#{src}&quot;
           )
         end
@@ -110,11 +110,11 @@ class Chef
       
         def remove_package(name, version)
           if version
-            run_command(
+            run_command_with_systems_locale(
               :command =&gt; &quot;#{gem_binary_path} uninstall #{name} -q -v \&quot;#{version}\&quot;&quot;
             )
           else
-            run_command(
+            run_command_with_systems_locale(
               :command =&gt; &quot;#{gem_binary_path} uninstall #{name} -q -a&quot;
             )
           end</diff>
      <filename>chef/lib/chef/provider/package/rubygems.rb</filename>
    </modified>
    <modified>
      <diff>@@ -106,9 +106,9 @@ class Chef
           end
         end
 
-        def initialize(node, new_resource)
+        def initialize(node, new_resource, collection=nil, definitions=nil, cookbook_loader=nil)
           @yum = YumCache.instance
-          super(node, new_resource)
+          super(node, new_resource, collection, definitions, cookbook_loader)
         end
       
         def load_current_resource
@@ -133,7 +133,7 @@ class Chef
         end
 
         def install_package(name, version)
-          run_command(
+          run_command_with_systems_locale(
             :command =&gt; &quot;yum -q -y install #{name}-#{version}&quot;
           )
           @yum.flush
@@ -142,7 +142,7 @@ class Chef
         def upgrade_package(name, version)
           # If we have a version, we can upgrade - otherwise, install
           if @current_resource.version
-            run_command(
+            run_command_with_systems_locale(
               :command =&gt; &quot;yum -q -y update #{name}-#{version}&quot;
             )   
             @yum.flush
@@ -153,11 +153,11 @@ class Chef
 
         def remove_package(name, version)
           if version
-            run_command(
+            run_command_with_systems_locale(
              :command =&gt; &quot;yum -q -y remove #{name}-#{version}&quot;
             )
           else
-            run_command(
+            run_command_with_systems_locale(
              :command =&gt; &quot;yum -q -y remove #{name}&quot;
             )
           end</diff>
      <filename>chef/lib/chef/provider/package/yum.rb</filename>
    </modified>
    <modified>
      <diff>@@ -55,23 +55,30 @@ class Chef
                        get_from_local_cookbook(source)
 
             # If the file exists
+            Chef::Log.debug &quot;#{@new_resource}: Checking for file existence of #{@new_resource.path}&quot;
             if ::File.exists?(@new_resource.path)
               # And it matches the checksum of the raw file
               @new_resource.checksum(self.checksum(raw_file.path))
+              Chef::Log.debug &quot;#{@new_resource}: File exists at #{@new_resource.path}&quot;
+              Chef::Log.debug &quot;#{@new_resource}: Target checksum: #{@current_resource.checksum}&quot;
+              Chef::Log.debug &quot;#{@new_resource}: Source checksum: #{@new_resource.checksum}&quot;
               if @new_resource.checksum != @current_resource.checksum
                 # Updating target file, let's perform a backup!
-                Chef::Log.debug(&quot;#{@new_resource} changed from #{@current_resource.checksum} to #{@new_resource.checksum}&quot;)
-                Chef::Log.info(&quot;Updating #{@new_resource} at #{@new_resource.path}&quot;)
-                backup(@new_resource.path)
+                Chef::Log.debug &quot;#{@new_resource}: checksum changed from #{@current_resource.checksum} to #{@new_resource.checksum}&quot;
+                Chef::Log.info &quot;#{@new_resource}: Updating #{@new_resource.path}&quot;
+                backup @new_resource.path
+                FileUtils.cp raw_file.path, @new_resource.path
+                @new_resource.updated = true
+              else
+                Chef::Log.debug &quot;#{@new_resource}: Target and Source checksums are the same, taking no action&quot;
               end
             else
               # We're creating a new file
-              Chef::Log.info(&quot;Creating #{@new_resource} at #{@new_resource.path}&quot;)
+              Chef::Log.info &quot;#{@new_resource}: Creating #{@new_resource.path}&quot;
+              FileUtils.cp raw_file.path, @new_resource.path
+              @new_resource.updated = true
             end
 
-            FileUtils.cp(raw_file.path, @new_resource.path)
-            @new_resource.updated = true
-
             # We're done with the file, so make sure to close it if it was open.
             raw_file.close unless raw_file.closed?
           rescue Net::HTTPRetriableError =&gt; e</diff>
      <filename>chef/lib/chef/provider/remote_file.rb</filename>
    </modified>
    <modified>
      <diff>@@ -25,8 +25,8 @@ class Chef
 
       include Chef::Mixin::Command
 
-      def initialize(node, new_resource)
-        super(node, new_resource)
+      def initialize(node, new_resource, collection=nil, definitions=nil, cookbook_loader=nil)
+        super(node, new_resource, collection, definitions, cookbook_loader)
         @enabled = nil
       end
 
@@ -35,6 +35,7 @@ class Chef
           Chef::Log.debug(&quot;#{@new_resource}: attempting to enable&quot;)
           status = enable_service()
           if status
+            @new_resource.updated = true
             Chef::Log.info(&quot;#{@new_resource}: enabled successfully&quot;)
           end
         else
@@ -47,6 +48,7 @@ class Chef
           Chef::Log.debug(&quot;#{@new_resource}: attempting to disable&quot;)
           status = disable_service()
           if status
+            @new_resource.updated = true
             Chef::Log.info(&quot;#{@new_resource}: disabled successfully&quot;)
           end
         else
@@ -59,6 +61,7 @@ class Chef
           Chef::Log.debug(&quot;#{@new_resource}: attempting to start&quot;)
           status = start_service()
           if status
+            @new_resource.updated = true
             Chef::Log.info(&quot;Started service #{@new_resource} successfully&quot;)
           end
         else
@@ -71,6 +74,7 @@ class Chef
           Chef::Log.debug(&quot;#{@new_resource}: attempting to stop&quot;)
           status = stop_service()
           if status
+            @new_resource.updated = true
             Chef::Log.info(&quot;#{@new_resource}: stopped successfully&quot;)
           end
         else
@@ -82,6 +86,7 @@ class Chef
         Chef::Log.debug(&quot;#{@new_resource}: attempting to restart&quot;)
         status = restart_service()
         if status
+          @new_resource.updated = true
           Chef::Log.info(&quot;#{@new_resource}: restarted successfully&quot;)
         end
       end
@@ -94,6 +99,7 @@ class Chef
             Chef::Log.debug(&quot;#{@new_resource}: attempting to reload&quot;)
             status = reload_service()
             if status
+              @new_resource.updated = true
               Chef::Log.info(&quot;#{@new_resource}: reloaded successfully&quot;)
             end
           end</diff>
      <filename>chef/lib/chef/provider/service.rb</filename>
    </modified>
    <modified>
      <diff>@@ -25,8 +25,8 @@ class Chef
     class Service
       class Init &lt; Chef::Provider::Service::Simple
         
-        def initialize(node, new_resource)
-          super(node, new_resource)
+        def initialize(node, new_resource, collection=nil, definitions=nil, cookbook_loader=nil)
+          super(node, new_resource, collection, definitions, cookbook_loader)
           @init_command = &quot;/etc/init.d/#{@new_resource.service_name}&quot;
         end
 </diff>
      <filename>chef/lib/chef/provider/service/init.rb</filename>
    </modified>
    <modified>
      <diff>@@ -25,8 +25,8 @@ class Chef
     class Service
       class Redhat &lt; Chef::Provider::Service::Init
         
-        def initialize(node, new_resource)
-           super(node, new_resource)
+        def initialize(node, new_resource, collection=nil, definitions=nil, cookbook_loader=nil)
+          super(node, new_resource, collection, definitions, cookbook_loader)
            @init_command = &quot;/sbin/service #{@new_resource.service_name}&quot;
          end
         </diff>
      <filename>chef/lib/chef/provider/service/redhat.rb</filename>
    </modified>
    <modified>
      <diff>@@ -39,6 +39,8 @@ class Chef
         
         cookbook_name = @new_resource.cookbook || @new_resource.cookbook_name
         
+        Chef::Log.debug(&quot;looking for template #{@new_resource.source} in cookbook #{cookbook_name.inspect}&quot;)
+        
         cache_file_name = &quot;cookbooks/#{cookbook_name}/templates/default/#{@new_resource.source}&quot;
         template_cache_name = &quot;#{cookbook_name}_#{@new_resource.source}&quot;
         </diff>
      <filename>chef/lib/chef/provider/template.rb</filename>
    </modified>
    <modified>
      <diff>@@ -29,8 +29,8 @@ class Chef
       
       attr_accessor :user_exists, :locked
       
-      def initialize(node, new_resource)
-        super(node, new_resource)
+      def initialize(node, new_resource, collection=nil, definitions=nil, cookbook_loader=nil)
+        super(node, new_resource, collection, definitions, cookbook_loader)
         @user_exists = true
         @locked = nil
       end</diff>
      <filename>chef/lib/chef/provider/user.rb</filename>
    </modified>
    <modified>
      <diff>@@ -1,6 +1,7 @@
 #
 # Author:: Adam Jacob (&lt;adam@opscode.com&gt;)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
+# Author:: Christopher Walters (&lt;cw@opscode.com&gt;)
+# Copyright:: Copyright (c) 2008, 2009 Opscode, Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the &quot;License&quot;);
@@ -20,6 +21,7 @@ require 'chef/resource'
 Dir[File.join(File.dirname(__FILE__), 'resource/**/*.rb')].sort.each { |lib| require lib }
 require 'chef/mixin/from_file'
 require 'chef/mixin/language'
+require 'chef/mixin/recipe_definition_dsl_core'
 require 'chef/resource_collection'
 require 'chef/cookbook_loader'
 require 'chef/rest'
@@ -30,7 +32,8 @@ class Chef
     
     include Chef::Mixin::FromFile
     include Chef::Mixin::Language
-        
+    include Chef::Mixin::RecipeDefinitionDSLCore
+    
     attr_accessor :cookbook_name, :recipe_name, :recipe, :node, :collection, 
                   :definitions, :params, :cookbook_loader
     
@@ -38,25 +41,9 @@ class Chef
       @cookbook_name = cookbook_name
       @recipe_name = recipe_name
       @node = node
-      
-      if collection
-        @collection = collection
-      else
-        @collection = Chef::ResourceCollection.new()
-      end
-      
-      if definitions
-        @definitions = definitions
-      else
-        @definitions = Hash.new
-      end
-      
-      if cookbook_loader
-        @cookbook_loader = cookbook_loader
-      else
-        @cookbook_loader = Chef::CookbookLoader.new()
-      end
-      
+      @collection = collection || Chef::ResourceCollection.new
+      @definitions = definitions || Hash.new
+      @cookbook_loader = cookbook_loader || Chef::CookbookLoader.new
       @params = Hash.new      
     end
     
@@ -152,59 +139,6 @@ class Chef
         @node[:tags].delete(tag)
       end
     end
-        
-    def method_missing(method_symbol, *args, &amp;block)
-      resource = nil
-      # If we have a definition that matches, we want to use that instead.  This should
-      # let you do some really crazy over-riding of &quot;native&quot; types, if you really want
-      # to. 
-      if @definitions.has_key?(method_symbol)
-        # This dupes the high level object, but we still need to dup the params
-        new_def = @definitions[method_symbol].dup
-        new_def.params = new_def.params.dup
-        new_def.node = @node
-        # This sets up the parameter overrides
-        new_def.instance_eval(&amp;block) if block
-        new_recipe = Chef::Recipe.new(@cookbook_name, @recipe_name, @node, @collection, @definitions, @cookbook_loader)
-        new_recipe.params = new_def.params
-        new_recipe.params[:name] = args[0]
-        new_recipe.instance_eval(&amp;new_def.recipe)
-      else
-        method_name = method_symbol.to_s
-        # Otherwise, we're rocking the regular resource call route.
-        rname = nil
-        regexp = %r{^(.+?)(_(.+))?$}
-
-        mn = method_name.match(regexp)
-        if mn
-          rname = &quot;Chef::Resource::#{mn[1].capitalize}&quot;
-
-          while mn &amp;&amp; mn[3]
-            mn = mn[3].match(regexp)          
-            rname &lt;&lt; mn[1].capitalize if mn
-          end
-        end
-
-        begin
-          args &lt;&lt; @collection
-          args &lt;&lt; @node
-          resource = eval(rname).new(*args)
-          # If we have a resource like this one, we want to steal it's state
-          resource.load_prior_resource
-          resource.cookbook_name = @cookbook_name
-          resource.recipe_name = @recipe_name
-          resource.params = @params
-          resource.instance_eval(&amp;block) if block
-        rescue Exception =&gt; e
-          if e.kind_of?(NameError) &amp;&amp; e.to_s =~ /Chef::Resource/
-            raise NameError, &quot;Cannot find #{rname} for #{method_name}\nOriginal: #{e.to_s}&quot;
-          else
-            raise e
-          end
-        end
-        @collection &lt;&lt; resource
-        resource
-      end
-    end
+    
   end
 end</diff>
      <filename>chef/lib/chef/recipe.rb</filename>
    </modified>
    <modified>
      <diff>@@ -1,5 +1,6 @@
 #
 # Author:: Adam Jacob (&lt;adam@opscode.com&gt;)
+# Author:: Christopher Walters (&lt;cw@opscode.com&gt;)
 # Copyright:: Copyright (c) 2008 Opscode, Inc.
 # License:: Apache License, Version 2.0
 #
@@ -19,6 +20,7 @@
 require 'chef/mixin/params_validate'
 require 'chef/mixin/check_helper'
 require 'chef/mixin/language'
+require 'chef/mixin/convert_to_class_name'
 require 'chef/resource_collection'
 require 'chef/node'
 
@@ -28,8 +30,9 @@ class Chef
     include Chef::Mixin::CheckHelper
     include Chef::Mixin::ParamsValidate
     include Chef::Mixin::Language
+    include Chef::Mixin::ConvertToClassName
     
-    attr_accessor :actions, :params, :provider, :updated, :allowed_actions, :collection, :cookbook_name, :recipe_name
+    attr_accessor :actions, :params, :provider, :updated, :allowed_actions, :collection, :cookbook_name, :recipe_name, :enclosing_provider
     attr_reader :resource_name, :source_line, :node
     
     def initialize(name, collection=nil, node=nil)
@@ -58,6 +61,17 @@ class Chef
         @source_line = ::File.expand_path(@source_line) if @source_line
       end
     end
+
+    # If an unknown method is invoked, determine whether the enclosing Provider's
+    # lexical scope can fulfill the request. E.g. This happens when the Resource's
+    # block invokes new_resource.
+    def method_missing(method_symbol, *args, &amp;block)
+      if enclosing_provider &amp;&amp; enclosing_provider.respond_to?(method_symbol)
+        enclosing_provider.send(method_symbol, *args, &amp;block)
+      else
+        raise NoMethodError, &quot;undefined method `#{method_symbol.to_s}' for #{self.class.to_s}&quot;
+      end
+    end
     
     def load_prior_resource
       begin
@@ -83,9 +97,14 @@ class Chef
     end
     
     def provider(arg=nil)
+      klass = if arg.kind_of?(String) || arg.kind_of?(Symbol)
+                lookup_provider_constant(arg)
+              else
+                arg
+              end
       set_or_return(
         :provider,
-        arg,
+        klass,
         :kind_of =&gt; [ Class ]
       )
     end
@@ -192,12 +211,12 @@ class Chef
       results.to_json(*a)
     end
     
-    def self.json_create(o)
-      resource = self.new(o[&quot;instance_vars&quot;][&quot;@name&quot;])
-      o[&quot;instance_vars&quot;].each do |k,v|
-        resource.instance_variable_set(k.to_sym, v)
+    def to_hash
+      instance_vars = Hash.new
+      self.instance_variables.each do |iv|
+        instance_vars[iv.sub(/^@/,'').to_sym] = self.instance_variable_get(iv) unless iv == &quot;@collection&quot;
       end
-      resource
+      instance_vars
     end
     
     def only_if(arg=nil, &amp;blk)
@@ -224,7 +243,101 @@ class Chef
       provider.send(&quot;action_#{action}&quot;)
     end
     
+    class &lt;&lt; self
+      
+      def json_create(o)
+        resource = self.new(o[&quot;instance_vars&quot;][&quot;@name&quot;])
+        o[&quot;instance_vars&quot;].each do |k,v|
+          resource.instance_variable_set(k.to_sym, v)
+        end
+        resource
+      end
+      
+      include Chef::Mixin::ConvertToClassName
+      
+      def attribute(attr_name, validation_opts={})
+        define_method(attr_name.to_sym) do |arg|
+          set_or_return(attr_name.to_sym, arg, validation_opts)
+        end
+      end
+      
+      def build_from_file(cookbook_name, filename)
+        rname = filename_to_qualified_string(cookbook_name, filename)
+          
+        new_resource_class = Class.new self do |cls|
+          
+          # default initialize method that ensures that when initialize is finally
+          # wrapped (see below), super is called in the event that the resource
+          # definer does not implement initialize
+          def initialize(name, collection=nil, node=nil)
+            super(name, collection, node)
+          end
+          
+          @actions_to_create = []
+          
+          class &lt;&lt; cls
+            include Chef::Mixin::FromFile
+            
+            def actions_to_create
+              @actions_to_create
+            end
+            
+            define_method(:actions) do |*action_names|
+              actions_to_create.push(*action_names)
+            end
+          end
+          
+          # load resource definition from file
+          cls.class_from_file(filename)
+          
+          # create a new constructor that wraps the old one and adds the actions
+          # specified in the DSL
+          old_init = instance_method(:initialize)
+
+          define_method(:initialize) do |name, *optional_args|
+            collection = optional_args.shift
+            node = optional_args.shift
+            @resource_name = rname.to_sym
+            old_init.bind(self).call(name, collection, node)
+            allowed_actions.push(self.class.actions_to_create).flatten!
+          end
+        end
+        
+        # register new class as a Chef::Resource
+        class_name = convert_to_class_name(rname)
+        Chef::Resource.const_set(class_name, new_resource_class)
+        Chef::Log.debug(&quot;Loaded contents of #{filename} into a resource named #{rname} defined in Chef::Resource::#{class_name}&quot;)
+        
+        new_resource_class
+      end
+      
+      # Resources that want providers namespaced somewhere other than 
+      # Chef::Provider can set the namespace with +provider_base+
+      # Ex:
+      #   class MyResource &lt; Chef::Resource
+      #     provider_base Chef::Provider::Deploy
+      #     # ...other stuff
+      #   end
+      def provider_base(arg=nil)
+        @provider_base ||= arg
+        @provider_base ||= Chef::Provider
+      end
+      
+    end
+    
     private
+    
+      def lookup_provider_constant(name)
+        begin
+          self.class.provider_base.const_get(convert_to_class_name(name.to_s))
+        rescue NameError =&gt; e
+          if e.to_s =~ /#{self.class.provider_base.to_s}/
+            raise ArgumentError, &quot;No provider found to match '#{name}'&quot;
+          else
+            raise e
+          end
+        end
+      end
       
       def check_timing(timing)
         unless timing == :delayed || timing == :immediate || timing == :immediately</diff>
      <filename>chef/lib/chef/resource.rb</filename>
    </modified>
    <modified>
      <diff>@@ -34,6 +34,10 @@ class Chef
         @weekday = &quot;*&quot;
         @command = nil
         @user = &quot;root&quot;
+        @mailto = nil
+        @path = nil
+        @shell = nil
+        @home = nil
       end
 
       def minute(arg=nil)
@@ -121,6 +125,38 @@ class Chef
         )
       end
 
+      def mailto(arg=nil)
+        set_or_return(
+          :mailto,
+          arg,
+          :kind_of =&gt; String
+        )
+      end
+
+      def path(arg=nil)
+        set_or_return(
+          :path,
+          arg,
+          :kind_of =&gt; String
+        )
+      end
+
+      def home(arg=nil)
+        set_or_return(
+          :home,
+          arg,
+          :kind_of =&gt; String
+        )
+      end
+
+      def shell(arg=nil)
+        set_or_return(
+          :shell,
+          arg,
+          :kind_of =&gt; String
+        )
+      end
+
       def command(arg=nil)
         set_or_return(
           :command,</diff>
      <filename>chef/lib/chef/resource/cron.rb</filename>
    </modified>
    <modified>
      <diff>@@ -55,6 +55,8 @@ class Chef
           :kind_of =&gt; [ Array ]
         )
       end
+
+      alias_method :users, :members
  
       def append(arg=nil)
         set_or_return(</diff>
      <filename>chef/lib/chef/resource/group.rb</filename>
    </modified>
    <modified>
      <diff>@@ -1,6 +1,7 @@
 #
 # Author:: Adam Jacob (&lt;adam@opscode.com&gt;)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
+# Author:: Christopher Walters (&lt;cw@opscode.com&gt;)
+# Copyright:: Copyright (c) 2008, 2009 Opscode, Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the &quot;License&quot;);
@@ -21,10 +22,11 @@ require 'chef/resource'
 class Chef
   class ResourceCollection
     include Enumerable
-    
+
     def initialize
       @resources = Array.new
       @resources_by_name = Hash.new
+      @insert_after_idx = nil
     end
     
     def [](index)
@@ -36,7 +38,7 @@ class Chef
       @resources[index] = arg 
       @resources_by_name[arg.to_s] = index
     end
-    
+
     def &lt;&lt;(*args)
       args.flatten.each do |a|
         is_chef_resource(a)
@@ -44,6 +46,25 @@ class Chef
         @resources_by_name[a.to_s] = @resources.length - 1 
       end
     end
+
+    def insert(resource)
+      is_chef_resource(resource)
+      if @insert_after_idx
+        # in the middle of executing a run, so any resources inserted now should
+        # be placed after the most recent addition done by the currently executing
+        # resource
+        @resources.insert(@insert_after_idx + 1, resource)
+        # update name -&gt; location mappings and register new resource
+        @resources_by_name.each_key do |key|
+          @resources_by_name[key] += 1 if @resources_by_name[key] &gt; @insert_after_idx
+        end
+        @resources_by_name[resource.to_s] = @insert_after_idx + 1
+        @insert_after_idx += 1
+      else  
+        @resources &lt;&lt; resource
+        @resources_by_name[resource.to_s] = @resources.length - 1
+      end
+    end
     
     def push(*args)
       args.flatten.each do |a|
@@ -58,6 +79,13 @@ class Chef
         yield r
       end
     end
+
+    def execute_each_resource
+      @resources.each_with_index do |r, idx|
+        @insert_after_idx = idx
+        yield r
+      end
+    end
     
     def each_index
       @resources.each_index do |i|
@@ -173,4 +201,4 @@ class Chef
         true
       end
   end
-end
\ No newline at end of file
+end</diff>
      <filename>chef/lib/chef/resource_collection.rb</filename>
    </modified>
    <modified>
      <diff>@@ -26,7 +26,7 @@ class Chef
     
     include Chef::Mixin::ParamsValidate
     
-    def initialize(node, collection)
+    def initialize(node, collection, definitions={}, cookbook_loader=nil)
       validate(
         {
           :node =&gt; node,
@@ -43,22 +43,49 @@ class Chef
       )
       @node = node
       @collection = collection
+      @definitions = definitions
+      @cookbook_loader = cookbook_loader
     end
     
     def build_provider(resource)
       provider_klass = resource.provider
       provider_klass ||= Chef::Platform.find_provider_for_node(@node, resource)
       Chef::Log.debug(&quot;#{resource} using #{provider_klass.to_s}&quot;)
-      provider = provider_klass.new(@node, resource)
+      provider = provider_klass.new(@node, resource, @collection, @definitions, @cookbook_loader)
       provider.load_current_resource
       provider
     end
-    
+
+    def run_action(resource, ra)
+      provider = build_provider(resource)
+      provider.send(&quot;action_#{ra}&quot;)
+
+      if resource.updated
+        resource.actions.each_key do |action|
+          if resource.actions[action].has_key?(:immediate)
+            resource.actions[action][:immediate].each do |r|
+              Chef::Log.info(&quot;#{resource} sending #{action} action to #{r} (immediate)&quot;)
+              run_action(r, action)
+            end
+          end
+          if resource.actions[action].has_key?(:delayed)
+            resource.actions[action][:delayed].each do |r|
+              @delayed_actions[r] = Hash.new unless @delayed_actions.has_key?(r)
+              @delayed_actions[r][action] = Array.new unless @delayed_actions[r].has_key?(action)
+              @delayed_actions[r][action] &lt;&lt; lambda {
+                Chef::Log.info(&quot;#{resource} sending #{action} action to #{r} (delayed)&quot;)
+              } 
+            end
+          end
+        end
+      end
+    end
+
     def converge
 
-      delayed_actions = Hash.new
+      @delayed_actions = Hash.new
       
-      @collection.each do |resource|
+      @collection.execute_each_resource do |resource|
         begin
           Chef::Log.debug(&quot;Processing #{resource}&quot;)
           
@@ -81,27 +108,7 @@ class Chef
           # Walk the actions for this resource, building the provider and running each.
           action_list = resource.action.kind_of?(Array) ? resource.action : [ resource.action ]
           action_list.each do |ra|
-            provider = build_provider(resource)
-            provider.send(&quot;action_#{ra}&quot;)
-            if resource.updated
-              resource.actions.each_key do |action|
-                if resource.actions[action].has_key?(:immediate)
-                  resource.actions[action][:immediate].each do |r|
-                    Chef::Log.info(&quot;#{resource} sending #{action} action to #{r} (immediate)&quot;)
-                    build_provider(r).send(&quot;action_#{action}&quot;)
-                  end
-                end
-                if resource.actions[action].has_key?(:delayed)
-                  resource.actions[action][:delayed].each do |r|
-                    delayed_actions[r] = Hash.new unless delayed_actions.has_key?(r)
-                    delayed_actions[r][action] = Array.new unless delayed_actions[r].has_key?(action)
-                    delayed_actions[r][action] &lt;&lt; lambda {
-                      Chef::Log.info(&quot;#{resource} sending #{action} action to #{r} (delayed)&quot;)
-                    } 
-                  end
-                end
-              end
-            end
+            run_action(resource, ra)
           end
         rescue =&gt; e
           Chef::Log.error(&quot;#{resource} (#{resource.source_line}) had an error:\n#{e}\n#{e.backtrace}&quot;)
@@ -110,10 +117,10 @@ class Chef
       end
       
       # Run all our :delayed actions
-      delayed_actions.each do |resource, action_hash| 
+      @delayed_actions.each do |resource, action_hash| 
         action_hash.each do |action, log_array|
           log_array.each { |l| l.call } # Call each log message
-          build_provider(resource).send(&quot;action_#{action}&quot;) 
+          run_action(resource, action)
         end
       end
 </diff>
      <filename>chef/lib/chef/runner.rb</filename>
    </modified>
    <modified>
      <diff>@@ -23,6 +23,11 @@ class Chef
         true
       end
   
+      def action_purr
+        @new_resource.updated = true
+        true
+      end
+
       def action_sell
         true
       end</diff>
      <filename>chef/spec/lib/chef/provider/snakeoil.rb</filename>
    </modified>
    <modified>
      <diff>@@ -32,11 +32,16 @@ describe Chef::Client, &quot;run&quot; do
       :register,
       :authenticate,
       :sync_library_files,
+      :sync_provider_files,
+      :sync_resource_files,
       :sync_attribute_files,
       :sync_definitions,
       :sync_recipes,
       :save_node,
-      :save_node
+      :save_node,
+      :run_ohai,
+      :safe_name,
+      :node_name
     ]
     to_stub.each do |method|
       @client.stub!(method).and_return(true)
@@ -88,6 +93,16 @@ describe Chef::Client, &quot;run&quot; do
     @client.run
   end
   
+  it &quot;should synchronize providers from the server&quot; do
+    @client.should_receive(:sync_provider_files).and_return(true)
+    @client.run
+  end
+  
+  it &quot;should synchronize resources from the server&quot; do
+    @client.should_receive(:sync_resource_files).and_return(true)
+    @client.run
+  end
+  
   it &quot;should save the nodes state on the server (twice!)&quot; do
     @client.should_receive(:save_node).exactly(3).times.and_return(true)
     @client.run
@@ -108,7 +123,9 @@ end
 describe Chef::Client, &quot;run_solo&quot; do
   before(:each) do
     @client = Chef::Client.new
-    @client.stub!(:build_node).and_return(true)
+    [:run_ohai, :safe_name, :node_name, :build_node].each do |method|
+      @client.stub!(method).and_return(true)
+    end
     Chef::Compile.stub!(:new).and_return(mock(&quot;Chef::Compile&quot;, :null_object =&gt; true))
     Chef::Runner.stub!(:new).and_return(mock(&quot;Chef::Runner&quot;, :null_object =&gt; true))
   end</diff>
      <filename>chef/spec/unit/client_spec.rb</filename>
    </modified>
    <modified>
      <diff>@@ -22,7 +22,15 @@ describe Chef::Compile do
   before(:each) do
     Chef::Config.node_path(File.join(File.dirname(__FILE__), &quot;..&quot;, &quot;data&quot;, &quot;compile&quot;, &quot;nodes&quot;))
     Chef::Config.cookbook_path(File.join(File.dirname(__FILE__), &quot;..&quot;, &quot;data&quot;, &quot;compile&quot;, &quot;cookbooks&quot;))
-    @compile = Chef::Compile.new
+    node = Chef::Node.new
+    node.stub!(:determine_node_name).and_return(true)
+    node.stub!(:load_libraries).and_return(true)
+    node.stub!(:load_providers).and_return(true)
+    node.stub!(:load_resources).and_return(true)
+    node.stub!(:load_attributes).and_return(true)
+    node.stub!(:load_definitions).and_return(true)
+    node.stub!(:load_recipes).and_return(true)
+    @compile = Chef::Compile.new(node)
   end
   
   it &quot;should create a new Chef::Compile&quot; do</diff>
      <filename>chef/spec/unit/compile_spec.rb</filename>
    </modified>
    <modified>
      <diff>@@ -29,6 +29,18 @@ describe Chef::Mixin::Command, &quot;popen4&quot; do
     end
   end
 
+  it &quot;should default all commands to be run in the POSIX standard C locale&quot; do
+    popen4(&quot;echo $LC_ALL&quot;) do |pid, stdin, stdout, stderr|
+      stdout.read.strip.should == &quot;C&quot;
+    end
+  end
+
+  it &quot;should respect locale when specified explicitly&quot; do
+    popen4(&quot;echo $LC_ALL&quot;, :environment =&gt; {&quot;LC_ALL&quot; =&gt; &quot;es&quot;}) do |pid, stdin, stdout, stderr|
+      stdout.read.strip.should == &quot;es&quot;
+    end
+  end
+
 end
 
 describe Chef::Mixin::Command, &quot;run_command&quot; do
@@ -45,4 +57,4 @@ describe Chef::Mixin::Command, &quot;run_command&quot; do
     end
   end
   
-end
\ No newline at end of file
+end</diff>
      <filename>chef/spec/unit/mixin/command_spec.rb</filename>
    </modified>
    <modified>
      <diff>@@ -36,6 +36,7 @@ describe Chef::Provider::Cron, &quot;load_current_resource&quot; do
     @node = mock(&quot;Chef::Node&quot;, :null_object =&gt; true)
     @new_resource = mock(&quot;Chef::Resource::Cron&quot;,
       :null_object =&gt; true,
+      :user =&gt; &quot;root&quot;,
       :name =&gt; &quot;foo&quot;,
       :minute =&gt; &quot;30&quot;,
       :command =&gt; &quot;/bin/true&quot;
@@ -69,8 +70,8 @@ describe Chef::Provider::Cron, &quot;load_current_resource&quot; do
     @stdout = mock(&quot;STDOUT&quot;, :null_object =&gt; true)    
     @stderr = mock(&quot;STDERR&quot;, :null_object =&gt; true)
     @pid = mock(&quot;PID&quot;, :null_object =&gt; true)
-    @stdout.stub!(:each).and_yield(&quot;# Chef Name: foo&quot;).
-      and_yield(&quot;* 5 * * * /bin/true&quot;)
+    @stdout.stub!(:each).and_yield(&quot;# Chef Name: foo\n&quot;).
+      and_yield(&quot;* 5 * * * /bin/true\n&quot;)
     @provider.stub!(:popen4).and_yield(@pid, @stdin, @stdout, @stderr).and_return(@status)
     Chef::Log.should_receive(:debug).with(&quot;Found cron '#{@new_resource.name}'&quot;)
     @provider.load_current_resource
@@ -78,6 +79,57 @@ describe Chef::Provider::Cron, &quot;load_current_resource&quot; do
         
 end
 
+describe Chef::Provider::Cron, &quot;compare_cron&quot; do
+  before(:each) do
+    @node = mock(&quot;Chef::Node&quot;, :null_object =&gt; true)
+    @new_resource = mock(&quot;Chef::Resource::Cron&quot;,
+      :null_object =&gt; true,
+      :user =&gt; &quot;root&quot;,
+      :name =&gt; &quot;foo&quot;,
+      :minute =&gt; &quot;30&quot;,
+      :hour =&gt; &quot;2&quot;,
+      :day =&gt; &quot;30&quot;,
+      :month =&gt; &quot;5&quot;,
+      :weekday =&gt; &quot;3&quot;,
+      :command =&gt; &quot;/bin/true&quot;,
+      :mailto =&gt; &quot;test@example.com&quot;,
+      :path =&gt; &quot;/usr/bin:/bin&quot;,
+      :shell =&gt; &quot;/bin/zsh&quot;,
+      :home =&gt; &quot;/home/thom&quot;
+    )
+    @current_resource = mock(&quot;Chef::Resource::Cron&quot;,
+      :null_object =&gt; true,
+      :user =&gt; &quot;root&quot;,
+      :name =&gt; &quot;foo&quot;,
+      :minute =&gt; &quot;30&quot;,
+      :hour =&gt; &quot;2&quot;,
+      :day =&gt; &quot;30&quot;,
+      :month =&gt; &quot;5&quot;,
+      :weekday =&gt; &quot;3&quot;,
+      :command =&gt; &quot;/bin/true&quot;,
+      :mailto =&gt; &quot;test@example.com&quot;,
+      :path =&gt; &quot;/usr/bin:/bin&quot;,
+      :shell =&gt; &quot;/bin/zsh&quot;,
+      :home =&gt; &quot;/home/thom&quot;
+    )
+    @provider = Chef::Provider::Cron.new(@node, @new_resource)
+    @provider.current_resource = @current_resource
+  end
+
+  %w{ minute hour day month weekday command mailto path shell home }.each do |attribute|
+    it &quot;should return true if #{attribute} doesn't match&quot; do 
+      @new_resource.should_receive(attribute).exactly(2).times.and_return(true)
+      @current_resource.should_receive(attribute).once.and_return(false)
+      @provider.compare_cron.should eql(true)
+    end
+  end
+
+  it &quot;should return false if the objects are identical&quot; do
+    @provider.compare_cron.should eql(false)
+  end
+end
+
+
 describe Chef::Provider::Cron, &quot;action_create&quot; do
   before(:each) do
     @node = mock(&quot;Chef::Node&quot;, :null_object =&gt; true)
@@ -85,16 +137,31 @@ describe Chef::Provider::Cron, &quot;action_create&quot; do
       :null_object =&gt; true,
       :name =&gt; &quot;foo&quot;,
       :minute =&gt; &quot;30&quot;,
+      :hour =&gt; &quot;*&quot;,
+      :day =&gt; &quot;*&quot;,
+      :month =&gt; &quot;*&quot;,
+      :weekday =&gt; &quot;*&quot;,
+      :mailto =&gt; nil,
+      :path =&gt; nil,
+      :shell =&gt; nil,
+      :home =&gt; nil,
       :command =&gt; &quot;/bin/true&quot;
     )
     @current_resource = mock(&quot;Chef::Resource::Cron&quot;,
       :null_object =&gt; true,
       :name =&gt; &quot;foo&quot;,
-      :minute =&gt; &quot;30&quot;,
+      :minute =&gt; &quot;*&quot;,
+      :hour =&gt; &quot;5&quot;,
+      :day =&gt; &quot;*&quot;,
+      :month =&gt; &quot;*&quot;,
+      :weekday =&gt; &quot;*&quot;,
+      :mailto =&gt; nil,
+      :path =&gt; nil,
+      :shell =&gt; nil,
+      :home =&gt; nil,
       :command =&gt; &quot;/bin/true&quot;
     )
     @provider = Chef::Provider::Cron.new(@node, @new_resource)
-
   end
 
   it &quot;should add the cron entry if cron exists&quot; do
@@ -103,10 +170,8 @@ describe Chef::Provider::Cron, &quot;action_create&quot; do
     @stdout = mock(&quot;STDOUT&quot;, :null_object =&gt; true)    
     @stderr = mock(&quot;STDERR&quot;, :null_object =&gt; true)
     @pid = mock(&quot;PID&quot;, :null_object =&gt; true)
-    @stdout.stub!(:each).and_yield(&quot;# Chef Name: bar&quot;).
-      and_yield(&quot;* 10 * * * /bin/false&quot;).
-      and_yield(&quot;# Chef Name: foo&quot;).
-      and_yield(&quot;* 5 * * * /bin/true&quot;)
+    @stdout.stub!(:each_line).and_yield(&quot;# Chef Name: bar\n&quot;).
+      and_yield(&quot;* 10 * * * /bin/false\n&quot;)
     @provider.stub!(:popen4).and_yield(@pid, @stdin, @stdout, @stderr).and_return(@status)
     Chef::Log.should_receive(:info).with(&quot;Added cron '#{@new_resource.name}'&quot;)
     @provider.action_create
@@ -118,10 +183,10 @@ describe Chef::Provider::Cron, &quot;action_create&quot; do
     @stdout = mock(&quot;STDOUT&quot;, :null_object =&gt; true)    
     @stderr = mock(&quot;STDERR&quot;, :null_object =&gt; true)
     @pid = mock(&quot;PID&quot;, :null_object =&gt; true)
-    @stdout.stub!(:each).and_yield(&quot;# Chef Name: bar&quot;).
-      and_yield(&quot;* 10 * * * /bin/false&quot;).
-      and_yield(&quot;# Chef Name: foo&quot;).
-      and_yield(&quot;* 5 * * * /bin/true&quot;)
+    @stdout.stub!(:each_line).and_yield(&quot;# Chef Name: bar\n&quot;).
+      and_yield(&quot;* 10 * * * /bin/false\n&quot;).
+      and_yield(&quot;# Chef Name: foo\n&quot;).
+      and_yield(&quot;* 5 * * * /bin/true\n&quot;)
     @provider.cron_empty=true
     @provider.stub!(:popen4).and_yield(@pid, @stdin, @stdout, @stderr).and_return(@status)
     Chef::Log.should_receive(:info).with(&quot;Added cron '#{@new_resource.name}'&quot;)
@@ -129,22 +194,61 @@ describe Chef::Provider::Cron, &quot;action_create&quot; do
   end
 
   it &quot;should update the cron entry if it exists and has changed&quot; do
+    @provider.current_resource = @current_resource
     @status = mock(&quot;Status&quot;, :exitstatus =&gt; 0)
     @stdin = mock(&quot;STDIN&quot;, :null_object =&gt; true)
     @stdout = mock(&quot;STDOUT&quot;, :null_object =&gt; true)    
     @stderr = mock(&quot;STDERR&quot;, :null_object =&gt; true)
     @pid = mock(&quot;PID&quot;, :null_object =&gt; true)
-    @stdout.stub!(:each).and_yield(&quot;# Chef Name: bar&quot;).
-      and_yield(&quot;* 10 * * * /bin/false&quot;).
-      and_yield(&quot;# Chef Name: foo&quot;).
-      and_yield(&quot;* 5 * * * /bin/true&quot;)
+    @stdout.stub!(:each_line).and_yield(&quot;# Chef Name: bar\n&quot;).
+      and_yield(&quot;* 10 * * * /bin/false\n&quot;).
+      and_yield(&quot;# Chef Name: foo\n&quot;).
+      and_yield(&quot;* 5 * * * /bin/true\n&quot;)
     @provider.cron_exists=true
     @provider.stub!(:popen4).and_yield(@pid, @stdin, @stdout, @stderr).and_return(@status)
     Chef::Log.should_receive(:info).with(&quot;Updated cron '#{@new_resource.name}'&quot;)
+    @provider.should_receive(:compare_cron).once.and_return(true)
     @provider.action_create
   end
 
   it &quot;should not update the cron entry if it exists and has not changed&quot; do
+    @status = mock(&quot;Status&quot;, :exitstatus =&gt; 0)
+    @stdin = mock(&quot;STDIN&quot;, :null_object =&gt; true)
+    @stdout = mock(&quot;STDOUT&quot;, :null_object =&gt; true)    
+    @stderr = mock(&quot;STDERR&quot;, :null_object =&gt; true)
+    @pid = mock(&quot;PID&quot;, :null_object =&gt; true)
+    @stdout.stub!(:each_line).and_yield(&quot;# Chef Name: bar\n&quot;).
+      and_yield(&quot;* 10 * * * /bin/false\n&quot;).
+      and_yield(&quot;# Chef Name: foo\n&quot;).
+      and_yield(&quot;30 * * * * /bin/true\n&quot;)
+    @provider.stub!(:popen4).and_yield(@pid, @stdin, @stdout, @stderr).and_return(@status)
+    Chef::Log.should_not_receive(:info).with(&quot;Updated cron '#{@new_resource.name}'&quot;)
+    Chef::Log.should_receive(:debug).with(&quot;Skipping existing cron entry '#{@new_resource.name}'&quot;)
+    @provider.should_receive(:compare_cron).once.and_return(false)
+    @provider.cron_exists = true
+    @provider.action_create
+  end
+
+  it &quot;should update the cron entry if it exists and has changed environment variables&quot; do
+    @provider.current_resource = @current_resource
+    @status = mock(&quot;Status&quot;, :exitstatus =&gt; 0)
+    @stdin = mock(&quot;STDIN&quot;, :null_object =&gt; true)
+    @stdout = mock(&quot;STDOUT&quot;, :null_object =&gt; true)    
+    @stderr = mock(&quot;STDERR&quot;, :null_object =&gt; true)
+    @pid = mock(&quot;PID&quot;, :null_object =&gt; true)
+    @stdout.stub!(:each_line).and_yield(&quot;# Chef Name: bar\n&quot;).
+      and_yield(&quot;* 10 * * * /bin/false\n&quot;).
+      and_yield(&quot;# Chef Name: foo\n&quot;).
+      and_yield(&quot;MAILTO=warn@example.com\n&quot;).
+      and_yield(&quot;30 * * * * /bin/true\n&quot;)
+    @provider.stub!(:popen4).and_yield(@pid, @stdin, @stdout, @stderr).and_return(@status)
+    Chef::Log.should_receive(:info).with(&quot;Updated cron '#{@new_resource.name}'&quot;)
+    @provider.cron_exists = true
+    @provider.should_receive(:compare_cron).once.and_return(true)
+    @provider.action_create
+  end
+
+  it &quot;should update the cron entry if it exists and has no environment variables&quot; do
     resource = mock(&quot;Chef::Resource::Cron&quot;,
       :null_object =&gt; true,
       :name =&gt; &quot;foo&quot;,
@@ -153,26 +257,31 @@ describe Chef::Provider::Cron, &quot;action_create&quot; do
       :day =&gt; &quot;*&quot;,
       :month =&gt; &quot;*&quot;,
       :weekday =&gt; &quot;*&quot;,
+      :mailto =&gt; &quot;test@example.com&quot;,
+      :path =&gt; nil,
+      :shell =&gt; nil,
+      :home =&gt; nil,
       :command =&gt; &quot;/bin/true&quot;
     )
     provider = Chef::Provider::Cron.new(@node, resource)
-
+    provider.current_resource = @current_resource
 
     @status = mock(&quot;Status&quot;, :exitstatus =&gt; 0)
     @stdin = mock(&quot;STDIN&quot;, :null_object =&gt; true)
     @stdout = mock(&quot;STDOUT&quot;, :null_object =&gt; true)    
     @stderr = mock(&quot;STDERR&quot;, :null_object =&gt; true)
     @pid = mock(&quot;PID&quot;, :null_object =&gt; true)
-    @stdout.stub!(:each_line).and_yield(&quot;# Chef Name: bar&quot;).
-      and_yield(&quot;* 10 * * * /bin/false&quot;).
+    @stdout.stub!(:each_line).and_yield(&quot;# Chef Name: bar\n&quot;).
+      and_yield(&quot;* 10 * * * /bin/false\n&quot;).
       and_yield(&quot;# Chef Name: foo\n&quot;).
       and_yield(&quot;30 * * * * /bin/true\n&quot;)
     provider.stub!(:popen4).and_yield(@pid, @stdin, @stdout, @stderr).and_return(@status)
-    Chef::Log.should_not_receive(:info).with(&quot;Updated cron '#{@new_resource.name}'&quot;)
-    Chef::Log.should_receive(:debug).with(&quot;Skipping existing cron entry '#{@new_resource.name}'&quot;)
+    Chef::Log.should_receive(:info).with(&quot;Updated cron '#{@new_resource.name}'&quot;)
     provider.cron_exists = true
+    provider.should_receive(:compare_cron).once.and_return(true)
     provider.action_create
   end
+
 end
 
 describe Chef::Provider::Cron, &quot;action_delete&quot; do
@@ -200,10 +309,10 @@ describe Chef::Provider::Cron, &quot;action_delete&quot; do
     @stdout = mock(&quot;STDOUT&quot;, :null_object =&gt; true)    
     @stderr = mock(&quot;STDERR&quot;, :null_object =&gt; true)
     @pid = mock(&quot;PID&quot;, :null_object =&gt; true)
-    @stdout.stub!(:each).and_yield(&quot;# Chef Name: bar&quot;).
-      and_yield(&quot;* 10 * * * /bin/false&quot;).
-      and_yield(&quot;# Chef Name: foo&quot;).
-      and_yield(&quot;* 30 * * * /bin/true&quot;)
+    @stdout.stub!(:each_line).and_yield(&quot;# Chef Name: bar\n&quot;).
+      and_yield(&quot;* 10 * * * /bin/false\n&quot;).
+      and_yield(&quot;# Chef Name: foo\n&quot;).
+      and_yield(&quot;* 30 * * * /bin/true\n&quot;)
     @provider.cron_exists=true
     @provider.stub!(:popen4).and_yield(@pid, @stdin, @stdout, @stderr).and_return(@status)
     Chef::Log.should_receive(:debug).with(&quot;Deleted cron '#{@new_resource.name}'&quot;)
@@ -217,7 +326,7 @@ describe Chef::Provider::Cron, &quot;action_delete&quot; do
     @stdout = mock(&quot;STDOUT&quot;, :null_object =&gt; true)    
     @stderr = mock(&quot;STDERR&quot;, :null_object =&gt; true)
     @pid = mock(&quot;PID&quot;, :null_object =&gt; true)
-    @stdout.stub!(:each).and_yield(&quot;# Chef Name: bar&quot;).
+    @stdout.stub!(:each_line).and_yield(&quot;# Chef Name: bar&quot;).
       and_yield(&quot;* 10 * * * /bin/false&quot;)
     @provider.stub!(:popen4).and_yield(@pid, @stdin, @stdout, @stderr).and_return(@status)
     Chef::Log.should_not_receive(:debug).with(&quot;Deleted cron '#{@new_resource.name}'&quot;)</diff>
      <filename>chef/spec/unit/provider/cron_spec.rb</filename>
    </modified>
    <modified>
      <diff>@@ -136,64 +136,33 @@ describe Chef::Provider::Group::Groupadd, &quot;modify_group_members&quot; do
     @provider = Chef::Provider::Group::Groupadd.new(@node, @new_resource)
     @provider.stub!(:run_command).and_return(true)
   end
-  
-  describe &quot;with an empty members array&quot; do
-    before do
-      @new_resource.stub!(:members).and_return([])
-    end
-    
-    it &quot;should log an appropriate message&quot; do
-      Chef::Log.should_receive(:debug).with(&quot;group[aj]: not changing group members, the group has no members&quot;)
-      @provider.modify_group_members
-    end
-  end
-  
-  describe &quot;with supplied members&quot; do
-    before do
-      @new_resource.stub!(:members).and_return([&quot;all&quot;, &quot;your&quot;, &quot;base&quot;])
-    end
-    
-    it &quot;should log an appropriate debug message&quot; do
-      Chef::Log.should_receive(:debug).with(&quot;group[aj]: setting group members to all, your, base&quot;)
-      @provider.modify_group_members
-    end
-    
-    it &quot;should run gpasswd with the members joined by ',' followed by the target group&quot; do
-      @provider.should_receive(:run_command).with({:command =&gt; &quot;gpasswd -M all,your,base aj&quot;})
-      @provider.modify_group_members
-    end
-    
-    it &quot;should run gpasswd individually for each user when the append option is set&quot; do
-      @new_resource.stub!(:append).and_return(true)
-      @provider.should_receive(:run_command).with({:command =&gt; &quot;gpasswd -a all aj&quot;})
-      @provider.should_receive(:run_command).with({:command =&gt; &quot;gpasswd -a your aj&quot;})
-      @provider.should_receive(:run_command).with({:command =&gt; &quot;gpasswd -a base aj&quot;})
-      @provider.modify_group_members
-    end
-    
+
+  it &quot;should raise an error when calling modify_group_members&quot; do
+    lambda { @provider.modify_group_members }.should raise_error(Chef::Exceptions::Group, &quot;you must override modify_group_members in #{@provider.to_s}&quot;)
   end
 end
 
-describe Chef::Provider::Group::Groupadd, &quot;load_current_resource&quot; do
+describe Chef::Provider::Group::Usermod, &quot;load_current_resource&quot; do
   before do
     @node = mock(&quot;Chef::Node&quot;, :null_object =&gt; true)
     @new_resource = mock(&quot;Chef::Resource::Group&quot;, :null_object =&gt; true, :group_name =&gt; &quot;aj&quot;)
-    @provider = Chef::Provider::Group::Groupadd.new(@node, @new_resource)
+    @provider = Chef::Provider::Group::Usermod.new(@node, @new_resource)
     File.stub!(:exists?).and_return(false)
   end
 
-  [ &quot;/usr/sbin/groupadd&quot;,
-    &quot;/usr/sbin/groupmod&quot;,
-    &quot;/usr/sbin/groupdel&quot;,
-    &quot;/usr/bin/gpasswd&quot; ].each do |required_binary|
-    it &quot;should raise an error if the required binary #{required_binary} doesn't exist&quot; do
-      File.should_receive(:exists?).with(&quot;/usr/sbin/groupadd&quot;).and_return(false)
-      lambda { @provider.load_current_resource }.should raise_error(Chef::Exceptions::Group)
-    end
-  end
-  
-  it &quot;shouldn't raise an error if the required binaries exist&quot; do
-    File.stub!(:exists?).and_return(true)
-    lambda { @provider.load_current_resource }.should_not raise_error(Chef::Exceptions::Group)
+  it &quot;should raise an error if the required binary /usr/sbin/groupadd doesn't exist&quot; do
+    File.should_receive(:exists?).with(&quot;/usr/sbin/groupadd&quot;).and_return(false)
+    lambda { @provider.load_current_resource }.should raise_error(Chef::Exceptions::Group)
+  end
+  it &quot;should raise an error if the required binary /usr/sbin/groupmod doesn't exist&quot; do
+    File.should_receive(:exists?).with(&quot;/usr/sbin/groupadd&quot;).and_return(true)
+    File.should_receive(:exists?).with(&quot;/usr/sbin/groupmod&quot;).and_return(false)
+    lambda { @provider.load_current_resource }.should raise_error(Chef::Exceptions::Group)
+  end
+  it &quot;should raise an error if the required binary /usr/sbin/groupdel doesn't exist&quot; do
+    File.should_receive(:exists?).with(&quot;/usr/sbin/groupadd&quot;).and_return(true)
+    File.should_receive(:exists?).with(&quot;/usr/sbin/groupmod&quot;).and_return(true)
+    File.should_receive(:exists?).with(&quot;/usr/sbin/groupdel&quot;).and_return(false)
+    lambda { @provider.load_current_resource }.should raise_error(Chef::Exceptions::Group)
   end
 end</diff>
      <filename>chef/spec/unit/provider/group/groupadd_spec.rb</filename>
    </modified>
    <modified>
      <diff>@@ -136,7 +136,7 @@ describe Chef::Provider::Package::Apt, &quot;install_package&quot; do
   end
   
   it &quot;should run apt-get install with the package name and version&quot; do
-    @provider.should_receive(:run_command).with({
+    @provider.should_receive(:run_command_with_systems_locale).with({
       :command =&gt; &quot;apt-get -q -y install emacs=1.0&quot;,
       :environment =&gt; {
         &quot;DEBIAN_FRONTEND&quot; =&gt; &quot;noninteractive&quot;
@@ -146,7 +146,7 @@ describe Chef::Provider::Package::Apt, &quot;install_package&quot; do
   end
 
   it &quot;should run apt-get install with the package name and version and options if specified&quot; do
-    @provider.should_receive(:run_command).with({
+    @provider.should_receive(:run_command_with_systems_locale).with({
       :command =&gt; &quot;apt-get -q -y --force-yes install emacs=1.0&quot;,
       :environment =&gt; {
         &quot;DEBIAN_FRONTEND&quot; =&gt; &quot;noninteractive&quot;
@@ -194,7 +194,7 @@ describe Chef::Provider::Package::Apt, &quot;remove_package&quot; do
   end
   
   it &quot;should run apt-get remove with the package name&quot; do
-    @provider.should_receive(:run_command).with({
+    @provider.should_receive(:run_command_with_systems_locale).with({
       :command =&gt; &quot;apt-get -q -y remove emacs&quot;,
       :environment =&gt; {
         &quot;DEBIAN_FRONTEND&quot; =&gt; &quot;noninteractive&quot;
@@ -204,7 +204,7 @@ describe Chef::Provider::Package::Apt, &quot;remove_package&quot; do
   end
 
   it &quot;should run apt-get remove with the package name and options if specified&quot; do
-    @provider.should_receive(:run_command).with({
+    @provider.should_receive(:run_command_with_systems_locale).with({
       :command =&gt; &quot;apt-get -q -y --force-yes remove emacs&quot;,
       :environment =&gt; {
         &quot;DEBIAN_FRONTEND&quot; =&gt; &quot;noninteractive&quot;
@@ -231,7 +231,7 @@ describe Chef::Provider::Package::Apt, &quot;purge_package&quot; do
   end
   
   it &quot;should run apt-get purge with the package name&quot; do
-    @provider.should_receive(:run_command).with({
+    @provider.should_receive(:run_command_with_systems_locale).with({
       :command =&gt; &quot;apt-get -q -y purge emacs&quot;,
       :environment =&gt; {
         &quot;DEBIAN_FRONTEND&quot; =&gt; &quot;noninteractive&quot;
@@ -241,7 +241,7 @@ describe Chef::Provider::Package::Apt, &quot;purge_package&quot; do
   end
 
   it &quot;should run apt-get purge with the package name and options if specified&quot; do
-    @provider.should_receive(:run_command).with({
+    @provider.should_receive(:run_command_with_systems_locale).with({
       :command =&gt; &quot;apt-get -q -y --force-yes purge emacs&quot;,
       :environment =&gt; {
         &quot;DEBIAN_FRONTEND&quot; =&gt; &quot;noninteractive&quot;
@@ -266,7 +266,7 @@ describe Chef::Provider::Package::Apt, &quot;preseed_package&quot; do
     )
     @provider = Chef::Provider::Package::Apt.new(@node, @new_resource)
     @provider.stub!(:get_preseed_file).and_return(&quot;/tmp/emacs-10.seed&quot;)
-    @provider.stub!(:run_command).and_return(true)
+    @provider.stub!(:run_command_with_systems_locale).and_return(true)
   end
   
   it &quot;should get the full path to the preseed response file&quot; do
@@ -275,7 +275,7 @@ describe Chef::Provider::Package::Apt, &quot;preseed_package&quot; do
   end
   
   it &quot;should run debconf-set-selections on the preseed file if it has changed&quot; do
-    @provider.should_receive(:run_command).with({
+    @provider.should_receive(:run_command_with_systems_locale).with({
       :command =&gt; &quot;debconf-set-selections /tmp/emacs-10.seed&quot;,
       :environment =&gt; {
         &quot;DEBIAN_FRONTEND&quot; =&gt; &quot;noninteractive&quot;
@@ -286,7 +286,7 @@ describe Chef::Provider::Package::Apt, &quot;preseed_package&quot; do
   
   it &quot;should not run debconf-set-selections if the preseed file has not changed&quot; do
     @provider.stub!(:get_preseed_file).and_return(false)
-    @provider.should_not_receive(:run_command)
+    @provider.should_not_receive(:run_command_with_systems_locale)
     @provider.preseed_package(&quot;emacs&quot;, &quot;10&quot;)
   end
 end</diff>
      <filename>chef/spec/unit/provider/package/apt_spec.rb</filename>
    </modified>
    <modified>
      <diff>@@ -29,16 +29,8 @@ describe Chef::Provider::Package::Dpkg, &quot;load_current_resource&quot; do
       :updated =&gt; nil,
       :source =&gt; &quot;/tmp/wget_1.11.4-1ubuntu1_amd64.deb&quot;
     )
-    @current_resource = mock(&quot;Chef::Resource::Package&quot;, 
-      :null_object =&gt; true,
-      :name =&gt; &quot;wget&quot;,
-      :version =&gt; nil,
-      :package_name =&gt; nil,
-      :updated =&gt; nil
-    )
 
     @provider = Chef::Provider::Package::Dpkg.new(@node, @new_resource)
-    Chef::Resource::Package.stub!(:new).and_return(@current_resource)
 
     @stdin = mock(&quot;STDIN&quot;, :null_object =&gt; true)
     @stdout = mock(&quot;STDOUT&quot;, :null_object =&gt; true)
@@ -51,15 +43,10 @@ describe Chef::Provider::Package::Dpkg, &quot;load_current_resource&quot; do
   end
   
   it &quot;should create a current resource with the name of the new_resource&quot; do
-    Chef::Resource::Package.should_receive(:new).and_return(@current_resource)
     @provider.load_current_resource
+    @provider.current_resource.package_name.should == &quot;wget&quot;
   end
   
-  it &quot;should set the current resources package name to the new resources package name&quot; do
-    @current_resource.should_receive(:package_name).with(@new_resource.package_name)
-    @provider.load_current_resource
-  end
-
   it &quot;should raise an exception if a source is supplied but not found&quot; do
     ::File.stub!(:exists?).and_return(false)
     lambda { @provider.load_current_resource }.should raise_error(Chef::Exceptions::Package)
@@ -68,9 +55,16 @@ describe Chef::Provider::Package::Dpkg, &quot;load_current_resource&quot; do
   it &quot;should get the source package version from dpkg-deb if provided&quot; do
     @stdout.stub!(:each).and_yield(&quot;wget\t1.11.4-1ubuntu1&quot;)
     @provider.stub!(:popen4).with(&quot;dpkg-deb -W #{@new_resource.source}&quot;).and_yield(@pid, @stdin, @stdout, @stderr).and_return(@status)
-    @current_resource.should_receive(:package_name).with(&quot;wget&quot;)
     @new_resource.should_receive(:version).with(&quot;1.11.4-1ubuntu1&quot;)
     @provider.load_current_resource
+    @provider.current_resource.package_name.should == &quot;wget&quot;
+  end
+  
+  it &quot;gets the source package name from dpkg-deb correctly when the package name has `-' or `+' characters&quot; do
+    @stdout.stub!(:each).and_yield(&quot;foo-pkg++2\t1.11.4-1ubuntu1&quot;)
+    @provider.stub!(:popen4).and_yield(@pid, @stdin, @stdout, @stderr).and_return(@status)
+    @provider.load_current_resource
+    @provider.current_resource.package_name.should == &quot;foo-pkg++2&quot;
   end
 
   it &quot;should raise an exception if the source is not set but we are installing&quot; do
@@ -99,11 +93,12 @@ describe Chef::Provider::Package::Dpkg, &quot;load_current_resource&quot; do
                                and_yield(&quot;Config-Version: 1.11.4-1ubuntu1&quot;).
                                and_yield(&quot;Depends: libc6 (&gt;= 2.8~20080505), libssl0.9.8 (&gt;= 0.9.8f-5)&quot;).
                                and_yield(&quot;Conflicts: wget-ssl&quot;)
-    @provider.stub!(:popen4).with(&quot;dpkg -s #{@current_resource.package_name}&quot;).and_yield(@pid, @stdin, @stdout, @stderr).and_return(@status)
-    @current_resource.should_receive(:version).with(&quot;1.11.4-1ubuntu1&quot;)
+    @provider.stub!(:popen4).with(&quot;dpkg -s wget&quot;).and_yield(@pid, @stdin, @stdout, @stderr).and_return(@status)
+    
     @provider.load_current_resource
+    @provider.current_resource.version.should == &quot;1.11.4-1ubuntu1&quot;
   end
-
+  
   it &quot;should raise an exception if dpkg fails to run&quot; do
     @status = mock(&quot;Status&quot;, :exitstatus =&gt; -1)
     @provider.stub!(:popen4).and_return(@status)
@@ -127,22 +122,20 @@ describe Chef::Provider::Package::Dpkg, &quot;install and upgrade&quot; do
   end
 
   it &quot;should run dpkg -i with the package source&quot; do
-    @provider.should_receive(:run_command).with({
+    @provider.should_receive(:run_command_with_systems_locale).with({
       :command =&gt; &quot;dpkg -i /tmp/wget_1.11.4-1ubuntu1_amd64.deb&quot;,
       :environment =&gt; {
-        &quot;DEBIAN_FRONTEND&quot; =&gt; &quot;noninteractive&quot;,
-        &quot;LANG&quot; =&gt; &quot;en_US&quot;
+        &quot;DEBIAN_FRONTEND&quot; =&gt; &quot;noninteractive&quot;
       }
     })
     @provider.install_package(&quot;wget&quot;, &quot;1.11.4-1ubuntu1&quot;)
   end
 
   it &quot;should run dpkg -i with the package source and options if specified&quot; do
-    @provider.should_receive(:run_command).with({
+    @provider.should_receive(:run_command_with_systems_locale).with({
       :command =&gt; &quot;dpkg -i --force-yes /tmp/wget_1.11.4-1ubuntu1_amd64.deb&quot;,
       :environment =&gt; {
-        &quot;DEBIAN_FRONTEND&quot; =&gt; &quot;noninteractive&quot;,
-        &quot;LANG&quot; =&gt; &quot;en_US&quot;
+        &quot;DEBIAN_FRONTEND&quot; =&gt; &quot;noninteractive&quot;
       }
     })
     @new_resource.stub!(:options).and_return(&quot;--force-yes&quot;)
@@ -170,22 +163,20 @@ describe Chef::Provider::Package::Dpkg, &quot;remove and purge&quot; do
   end
 
   it &quot;should run dpkg -r to remove the package&quot; do
-    @provider.should_receive(:run_command).with({
+    @provider.should_receive(:run_command_with_systems_locale).with({
       :command =&gt; &quot;dpkg -r wget&quot;,
       :environment =&gt; {
-        &quot;DEBIAN_FRONTEND&quot; =&gt; &quot;noninteractive&quot;,
-        &quot;LANG&quot; =&gt; &quot;en_US&quot;
+        &quot;DEBIAN_FRONTEND&quot; =&gt; &quot;noninteractive&quot;
       }
     })
     @provider.remove_package(&quot;wget&quot;, &quot;1.11.4-1ubuntu1&quot;)
   end
 
   it &quot;should run dpkg -r to remove the package with options if specified&quot; do
-    @provider.should_receive(:run_command).with({
+    @provider.should_receive(:run_command_with_systems_locale).with({
       :command =&gt; &quot;dpkg -r --force-yes wget&quot;,
       :environment =&gt; {
-        &quot;DEBIAN_FRONTEND&quot; =&gt; &quot;noninteractive&quot;,
-        &quot;LANG&quot; =&gt; &quot;en_US&quot;
+        &quot;DEBIAN_FRONTEND&quot; =&gt; &quot;noninteractive&quot;
       }
     })
     @new_resource.stub!(:options).and_return(&quot;--force-yes&quot;)
@@ -194,22 +185,20 @@ describe Chef::Provider::Package::Dpkg, &quot;remove and purge&quot; do
   end
 
   it &quot;should run dpkg -P to purge the package&quot; do
-    @provider.should_receive(:run_command).with({
+    @provider.should_receive(:run_command_with_systems_locale).with({
       :command =&gt; &quot;dpkg -P wget&quot;,
       :environment =&gt; {
-        &quot;DEBIAN_FRONTEND&quot; =&gt; &quot;noninteractive&quot;,
-        &quot;LANG&quot; =&gt; &quot;en_US&quot;
+        &quot;DEBIAN_FRONTEND&quot; =&gt; &quot;noninteractive&quot;
       }
     })
     @provider.purge_package(&quot;wget&quot;, &quot;1.11.4-1ubuntu1&quot;)
   end
 
   it &quot;should run dpkg -P to purge the package with options if specified&quot; do
-    @provider.should_receive(:run_command).with({
+    @provider.should_receive(:run_command_with_systems_locale).with({
       :command =&gt; &quot;dpkg -P --force-yes wget&quot;,
       :environment =&gt; {
-        &quot;DEBIAN_FRONTEND&quot; =&gt; &quot;noninteractive&quot;,
-        &quot;LANG&quot; =&gt; &quot;en_US&quot;
+        &quot;DEBIAN_FRONTEND&quot; =&gt; &quot;noninteractive&quot;
       }
     })
     @new_resource.stub!(:options).and_return(&quot;--force-yes&quot;)</diff>
      <filename>chef/spec/unit/provider/package/dpkg_spec.rb</filename>
    </modified>
    <modified>
      <diff>@@ -138,7 +138,7 @@ describe Chef::Provider::Package::Freebsd, &quot;install_package&quot; do
   end
 
   it &quot;should run pkg_add -r with the package name&quot; do
-    @provider.should_receive(:run_command).with({
+    @provider.should_receive(:run_command_with_systems_locale).with({
       :command =&gt; &quot;pkg_add -r zsh&quot;,
     })
     @provider.install_package(&quot;zsh&quot;, &quot;4.3.6_7&quot;)
@@ -147,28 +147,34 @@ describe Chef::Provider::Package::Freebsd, &quot;install_package&quot; do
   it &quot;should run make install when installing from ports&quot; do
     @new_resource.stub!(:source).and_return(&quot;ports&quot;)
     @provider.should_receive(:port_path).and_return(&quot;/usr/ports/shells/zsh&quot;)
-    @provider.should_receive(:run_command).with(:command =&gt; &quot;make -DBATCH install&quot;, :cwd =&gt; &quot;/usr/ports/shells/zsh&quot;)
+    @provider.should_receive(:run_command_with_systems_locale).with(:command =&gt; &quot;make -DBATCH install&quot;, :cwd =&gt; &quot;/usr/ports/shells/zsh&quot;)
     @provider.install_package(&quot;zsh&quot;, &quot;4.3.6_7&quot;)
   end
 end
 
 describe Chef::Provider::Package::Freebsd, &quot;port path&quot; do
   it &quot;should figure out the port path from the package_name using whereis&quot; do
-    @new_resource = mock(&quot;Chef::Resource::Package&quot;, :package_name =&gt; &quot;zsh&quot;)
+    @new_resource = mock( &quot;Chef::Resource::Package&quot;, 
+                          :package_name =&gt; &quot;zsh&quot;, 
+                          :cookbook_name =&gt; &quot;adventureclub&quot;)
     @provider = Chef::Provider::Package::Freebsd.new(mock(&quot;Chef::Node&quot;), @new_resource)
     @provider.should_receive(:popen4).with(&quot;whereis -s zsh&quot;).and_yield(nil, nil, [&quot;zsh: /usr/ports/shells/zsh&quot;], nil)
     @provider.port_path.should == &quot;/usr/ports/shells/zsh&quot;
   end
   
   it &quot;should use the package_name as the port path when it starts with /&quot; do
-    @new_resource = mock(&quot;Chef::Resource::Package&quot;, :package_name =&gt; &quot;/usr/ports/www/wordpress&quot;)
+    @new_resource = mock( &quot;Chef::Resource::Package&quot;, 
+                          :package_name =&gt; &quot;/usr/ports/www/wordpress&quot;,
+                          :cookbook_name =&gt; &quot;adventureclub&quot;)
     @provider = Chef::Provider::Package::Freebsd.new(mock(&quot;Chef::Node&quot;), @new_resource)
     @provider.should_not_receive(:popen4)
     @provider.port_path.should == &quot;/usr/ports/www/wordpress&quot;
   end
   
   it &quot;should use the package_name as a relative path from /usr/ports when it contains / but doesn't start with it&quot; do
-    @new_resource = mock(&quot;Chef::Resource::Package&quot;, :package_name =&gt; &quot;www/wordpress&quot;)
+    @new_resource = mock( &quot;Chef::Resource::Package&quot;, 
+                          :package_name =&gt; &quot;www/wordpress&quot;,
+                          :cookbook_name =&gt; &quot;xenoparadox&quot;)
     @provider = Chef::Provider::Package::Freebsd.new(mock(&quot;Chef::Node&quot;), @new_resource)
     @provider.should_not_receive(:popen4)
     @provider.port_path.should == &quot;/usr/ports/www/wordpress&quot;
@@ -198,13 +204,13 @@ describe Chef::Provider::Package::Freebsd, &quot;ruby-iconv (package with a dash in t
   end
 
   it &quot;should run pkg_add -r with the package name&quot; do
-    @provider.should_receive(:run_command).with(:command =&gt; &quot;pkg_add -r ruby18-iconv&quot;)
+    @provider.should_receive(:run_command_with_systems_locale).with(:command =&gt; &quot;pkg_add -r ruby18-iconv&quot;)
     @provider.install_package(&quot;ruby-iconv&quot;, &quot;1.0&quot;)
   end
 
   it &quot;should run make install when installing from ports&quot; do
     @new_resource.stub!(:source).and_return(&quot;ports&quot;)
-    @provider.should_receive(:run_command).with(:command =&gt; &quot;make -DBATCH install&quot;, :cwd =&gt; &quot;/usr/ports/converters/ruby-iconv&quot;)
+    @provider.should_receive(:run_command_with_systems_locale).with(:command =&gt; &quot;make -DBATCH install&quot;, :cwd =&gt; &quot;/usr/ports/converters/ruby-iconv&quot;)
     @provider.install_package(&quot;ruby-iconv&quot;, &quot;1.0&quot;)
   end
 end
@@ -230,7 +236,7 @@ describe Chef::Provider::Package::Freebsd, &quot;remove_package&quot; do
   end
 
   it &quot;should run pkg_delete with the package name and version&quot; do
-    @provider.should_receive(:run_command).with({
+    @provider.should_receive(:run_command_with_systems_locale).with({
       :command =&gt; &quot;pkg_delete zsh-4.3.6_7&quot;
     })
     @provider.remove_package(&quot;zsh&quot;, &quot;4.3.6_7&quot;)
@@ -274,7 +280,7 @@ describe Chef::Provider::Package::Freebsd, &quot;install_package latest link fixes&quot; d
     @provider.stub!(:package_name).and_return(&quot;perl&quot;)
     @provider.stub!(:latest_link_name).and_return(&quot;perl&quot;)
 
-    @provider.should_receive(:run_command).with({
+    @provider.should_receive(:run_command_with_systems_locale).with({
       :command =&gt; &quot;pkg_add -r perl&quot;,
     })
     @provider.install_package(&quot;perl5.8&quot;, &quot;5.8.8_1&quot;)
@@ -299,7 +305,7 @@ describe Chef::Provider::Package::Freebsd, &quot;install_package latest link fixes&quot; d
     @provider.stub!(:package_name).and_return(&quot;mysql-server&quot;)
     @provider.stub!(:latest_link_name).and_return(&quot;mysql50-server&quot;)
 
-    @provider.should_receive(:run_command).with({
+    @provider.should_receive(:run_command_with_systems_locale).with({
       :command =&gt; &quot;pkg_add -r mysql50-server&quot;,
     })
     @provider.install_package(&quot;mysql50-server&quot;, &quot;5.0.45_1&quot;)</diff>
      <filename>chef/spec/unit/provider/package/freebsd_spec.rb</filename>
    </modified>
    <modified>
      <diff>@@ -113,7 +113,7 @@ EOF
     it &quot;should run the port install command with the correct version&quot; do
       @current_resource.should_receive(:version).and_return(&quot;4.1.6&quot;)
       @provider.current_resource = @current_resource
-      @provider.should_receive(:run_command).with(:command =&gt; &quot;port install zsh @4.2.7&quot;)
+      @provider.should_receive(:run_command_with_systems_locale).with(:command =&gt; &quot;port install zsh @4.2.7&quot;)
 
       @provider.install_package(&quot;zsh&quot;, &quot;4.2.7&quot;)
     end
@@ -121,7 +121,7 @@ EOF
     it &quot;should not do anything if a package already exists with the same version&quot; do
       @current_resource.should_receive(:version).and_return(&quot;4.2.7&quot;)
       @provider.current_resource = @current_resource
-      @provider.should_not_receive(:run_command)
+      @provider.should_not_receive(:run_command_with_systems_locale)
 
       @provider.install_package(&quot;zsh&quot;, &quot;4.2.7&quot;)
     end
@@ -129,24 +129,24 @@ EOF
 
   describe &quot;purge_package&quot; do
     it &quot;should run the port uninstall command with the correct version&quot; do
-      @provider.should_receive(:run_command).with(:command =&gt; &quot;port uninstall zsh @4.2.7&quot;)
+      @provider.should_receive(:run_command_with_systems_locale).with(:command =&gt; &quot;port uninstall zsh @4.2.7&quot;)
       @provider.purge_package(&quot;zsh&quot;, &quot;4.2.7&quot;)
     end
 
     it &quot;should purge the currently active version if no explicit version is passed in&quot; do
-      @provider.should_receive(:run_command).with(:command =&gt; &quot;port uninstall zsh&quot;)
+      @provider.should_receive(:run_command_with_systems_locale).with(:command =&gt; &quot;port uninstall zsh&quot;)
       @provider.purge_package(&quot;zsh&quot;, nil)
     end
   end
 
   describe &quot;remove_package&quot; do
     it &quot;should run the port deactivate command with the correct version&quot; do
-      @provider.should_receive(:run_command).with(:command =&gt; &quot;port deactivate zsh @4.2.7&quot;)
+      @provider.should_receive(:run_command_with_systems_locale).with(:command =&gt; &quot;port deactivate zsh @4.2.7&quot;)
       @provider.remove_package(&quot;zsh&quot;, &quot;4.2.7&quot;)
     end
 
     it &quot;should remove the currently active version if no explicit version is passed in&quot; do
-      @provider.should_receive(:run_command).with(:command =&gt; &quot;port deactivate zsh&quot;)
+      @provider.should_receive(:run_command_with_systems_locale).with(:command =&gt; &quot;port deactivate zsh&quot;)
       @provider.remove_package(&quot;zsh&quot;, nil)
     end
   end
@@ -156,7 +156,7 @@ EOF
       @current_resource.should_receive(:version).at_least(:once).and_return(&quot;4.1.6&quot;)
       @provider.current_resource = @current_resource
 
-      @provider.should_receive(:run_command).with(:command =&gt; &quot;port upgrade zsh @4.2.7&quot;)
+      @provider.should_receive(:run_command_with_systems_locale).with(:command =&gt; &quot;port upgrade zsh @4.2.7&quot;)
 
       @provider.upgrade_package(&quot;zsh&quot;, &quot;4.2.7&quot;)
     end
@@ -164,7 +164,7 @@ EOF
     it &quot;should not run the port upgrade command if the version is already installed&quot; do
       @current_resource.should_receive(:version).at_least(:once).and_return(&quot;4.2.7&quot;)
       @provider.current_resource = @current_resource
-      @provider.should_not_receive(:run_command)
+      @provider.should_not_receive(:run_command_with_systems_locale)
 
       @provider.upgrade_package(&quot;zsh&quot;, &quot;4.2.7&quot;)
     end</diff>
      <filename>chef/spec/unit/provider/package/macports_spec.rb</filename>
    </modified>
    <modified>
      <diff>@@ -117,21 +117,21 @@ describe Chef::Provider::Package::Portage, &quot;install_package&quot; do
   end
 
   it &quot;should install a normally versioned package using portage&quot; do
-    @provider.should_receive(:run_command).with({
+    @provider.should_receive(:run_command_with_systems_locale).with({
       :command =&gt; &quot;emerge -g --color n --nospinner --quiet =dev-util/git-1.0.0&quot;
     })
     @provider.install_package(&quot;dev-util/git&quot;, &quot;1.0.0&quot;)
   end
 
   it &quot;should install a tilde versioned package using portage&quot; do
-    @provider.should_receive(:run_command).with({
+    @provider.should_receive(:run_command_with_systems_locale).with({
       :command =&gt; &quot;emerge -g --color n --nospinner --quiet ~dev-util/git-1.0.0&quot;
     })
     @provider.install_package(&quot;dev-util/git&quot;, &quot;~1.0.0&quot;)
   end
 
   it &quot;should add options to the emerge command when specified&quot; do
-    @provider.should_receive(:run_command).with({
+    @provider.should_receive(:run_command_with_systems_locale).with({
       :command =&gt; &quot;emerge -g --color n --nospinner --quiet --oneshot =dev-util/git-1.0.0&quot;
     })
     @new_resource.stub!(:options).and_return(&quot;--oneshot&quot;)
@@ -156,14 +156,14 @@ describe Chef::Provider::Package::Portage, &quot;remove_package&quot; do
   end
 
   it &quot;should un-emerge the package with no version specified&quot; do
-    @provider.should_receive(:run_command).with({
+    @provider.should_receive(:run_command_with_systems_locale).with({
       :command =&gt; &quot;emerge --unmerge --color n --nospinner --quiet dev-util/git&quot;
     })
     @provider.remove_package(&quot;dev-util/git&quot;, nil)
   end
 
   it &quot;should un-emerge the package with a version specified&quot; do
-    @provider.should_receive(:run_command).with({
+    @provider.should_receive(:run_command_with_systems_locale).with({
       :command =&gt; &quot;emerge --unmerge --color n --nospinner --quiet =dev-util/git-1.0.0&quot;
     })
     @provider.remove_package(&quot;dev-util/git&quot;, &quot;1.0.0&quot;)</diff>
      <filename>chef/spec/unit/provider/package/portage_spec.rb</filename>
    </modified>
    <modified>
      <diff>@@ -114,14 +114,14 @@ describe Chef::Provider::Package::Rpm, &quot;install and upgrade&quot; do
   end
   
   it &quot;should run rpm -i with the package source to install&quot; do
-    @provider.should_receive(:run_command).with({
+    @provider.should_receive(:run_command_with_systems_locale).with({
       :command =&gt; &quot;rpm -i /tmp/emacs-21.4-20.el5.i386.rpm&quot;
     })
     @provider.install_package(&quot;emacs&quot;, &quot;21.4-20.el5&quot;)
   end
   
   it &quot;should run rpm -U with the package source to upgrade&quot; do
-    @provider.should_receive(:run_command).with({
+    @provider.should_receive(:run_command_with_systems_locale).with({
       :command =&gt; &quot;rpm -U /tmp/emacs-21.4-20.el5.i386.rpm&quot;
     })
     @provider.upgrade_package(&quot;emacs&quot;, &quot;21.4-20.el5&quot;)
@@ -142,7 +142,7 @@ describe Chef::Provider::Package::Rpm, &quot;remove&quot; do
   end
 
   it &quot;should run rpm -e to remove the package&quot; do
-    @provider.should_receive(:run_command).with({
+    @provider.should_receive(:run_command_with_systems_locale).with({
       :command =&gt; &quot;rpm -e emacs-21.4-20.el5&quot;
     })
     @provider.remove_package(&quot;emacs&quot;, &quot;21.4-20.el5&quot;)</diff>
      <filename>chef/spec/unit/provider/package/rpm_spec.rb</filename>
    </modified>
    <modified>
      <diff>@@ -60,8 +60,11 @@ describe Chef::Provider::Package::Rubygems, &quot;install_package&quot; do
 
   it &quot;should run gem install with the package name and version&quot; do
     @provider.should_receive(:run_command).with({
-      :command =&gt; &quot;gem install rspec -q --no-rdoc --no-ri -v \&quot;1.2.2\&quot;&quot;
+      :command =&gt; &quot;gem install rspec -q --no-rdoc --no-ri -v \&quot;1.2.2\&quot;&quot;,
+      :environment =&gt; {
+        &quot;LC_ALL&quot; =&gt; nil
+      }
     })
     @provider.install_package(&quot;rspec&quot;, &quot;1.2.2&quot;)
   end
-end
\ No newline at end of file
+end</diff>
      <filename>chef/spec/unit/provider/package/rubygems_spec.rb</filename>
    </modified>
    <modified>
      <diff>@@ -104,7 +104,7 @@ describe Chef::Provider::Package::Yum, &quot;install_package&quot; do
   end
   
   it &quot;should run yum install with the package name and version&quot; do
-    @provider.should_receive(:run_command).with({
+    @provider.should_receive(:run_command_with_systems_locale).with({
       :command =&gt; &quot;yum -q -y install emacs-1.0&quot;
     })
     @provider.install_package(&quot;emacs&quot;, &quot;1.0&quot;)
@@ -143,7 +143,7 @@ describe Chef::Provider::Package::Yum, &quot;upgrade_package&quot; do
   end
   
   it &quot;should run yum update if the package is installed&quot; do
-    @provider.should_receive(:run_command).with({
+    @provider.should_receive(:run_command_with_systems_locale).with({
       :command =&gt; &quot;yum -q -y update emacs-11&quot;
     })
     @provider.upgrade_package(@new_resource.name, @provider.candidate_version)
@@ -151,7 +151,7 @@ describe Chef::Provider::Package::Yum, &quot;upgrade_package&quot; do
   
   it &quot;should run yum install if the package is not installed&quot; do
     @current_resource.stub!(:version).and_return(nil)
-    @provider.should_receive(:run_command).with({
+    @provider.should_receive(:run_command_with_systems_locale).with({
       :command =&gt; &quot;yum -q -y install emacs-11&quot;
     })
     @provider.upgrade_package(@new_resource.name, @provider.candidate_version)
@@ -180,7 +180,7 @@ describe Chef::Provider::Package::Yum, &quot;remove_package&quot; do
   end
   
   it &quot;should run yum remove with the package name&quot; do
-    @provider.should_receive(:run_command).with({
+    @provider.should_receive(:run_command_with_systems_locale).with({
       :command =&gt; &quot;yum -q -y remove emacs-1.0&quot;
     })
     @provider.remove_package(&quot;emacs&quot;, &quot;1.0&quot;)
@@ -209,7 +209,7 @@ describe Chef::Provider::Package::Yum, &quot;purge_package&quot; do
   end
   
   it &quot;should run yum remove with the package name&quot; do
-    @provider.should_receive(:run_command).with({
+    @provider.should_receive(:run_command_with_systems_locale).with({
       :command =&gt; &quot;yum -q -y remove emacs-1.0&quot;    
     })
     @provider.purge_package(&quot;emacs&quot;, &quot;1.0&quot;)</diff>
      <filename>chef/spec/unit/provider/package/yum_spec.rb</filename>
    </modified>
    <modified>
      <diff>@@ -165,34 +165,57 @@ describe Chef::Provider::RemoteFile, &quot;do_remote_file&quot; do
     @provider.should_receive(:checksum).with(@tempfile.path).and_return(&quot;0fd012fdc96e96f8f7cf2046522a54aed0ce470224513e45da6bc1a17a4924aa&quot;)
     do_remote_file
   end
+
+  describe &quot;when the target file does not exist&quot; do
+    before do
+      ::File.stub!(:exists?).with(@resource.path).and_return(false)
+      @provider.stub!(:get_from_server).and_return(@tempfile)
+    end
+
+    it &quot;should copy the raw file to the new resource&quot; do
+      FileUtils.should_receive(:cp).with(@tempfile.path, @resource.path).and_return(true)    
+      do_remote_file
+    end
+
+    it &quot;should set the new resource to updated&quot; do
+      @resource.should_receive(:updated=).with(true)    
+      do_remote_file
+    end
+  end
   
   describe &quot;when the target file already exists&quot; do
     before do
-      ::File.stub!(:exists?).and_return(true)
+      ::File.stub!(:exists?).with(@resource.path).and_return(true)
       @provider.stub!(:get_from_server).and_return(@tempfile)
     end
 
-    it &quot;should backup the original file if it is different&quot; do
-      @provider.current_resource.checksum(&quot;0fd012fdc96e96f8f7cf2046522a54aed0ce470224513e45da6bc1a17a4924ab&quot;)
-      @provider.should_receive(:backup).with(@resource.path).and_return(true)
-      do_remote_file
+    describe &quot;and the checksum doesn't match&quot; do
+      before do
+        @provider.
+          current_resource.
+          checksum(&quot;0fd012fdc96e96f8f7cf2046522a54aed0ce470224513e45da6bc1a17a4924ab&quot;)
+      end
+
+      it &quot;should backup the original file&quot; do
+        @provider.should_receive(:backup).with(@resource.path).and_return(true)
+        do_remote_file
+      end
+
+      it &quot;should copy the raw file to the new resource&quot; do
+        FileUtils.should_receive(:cp).with(@tempfile.path, @resource.path).and_return(true)    
+        do_remote_file
+      end
+
+      it &quot;should set the new resource to updated&quot; do
+        @resource.should_receive(:updated=).with(true)    
+        do_remote_file
+      end
     end
 
     it &quot;shouldn't backup the original file when it's the same&quot; do
       @provider.should_not_receive(:backup).with(@resource.path).and_return(true)
       do_remote_file
     end
-
-  end
-  
-  it &quot;should set the new resource to updated&quot; do
-    @resource.should_receive(:updated=).with(true)    
-    do_remote_file
-  end
-  
-  it &quot;should copy the raw file to the new resource&quot; do
-    FileUtils.should_receive(:cp).with(@tempfile.path, @resource.path).and_return(true)    
-    do_remote_file
   end
   
   it &quot;should set the owner if provided&quot; do</diff>
      <filename>chef/spec/unit/provider/remote_file_spec.rb</filename>
    </modified>
    <modified>
      <diff>@@ -51,17 +51,20 @@ describe Chef::Provider::Service, &quot;action_enable&quot; do
     @provider.stub!(:enable_service).and_return(true)
   end
 
-  it &quot;should enable the service if disabled&quot; do
+  it &quot;should enable the service if disabled and set the resource as updated&quot; do
     @current_resource.stub!(:enabled).and_return(false)
     @provider.should_receive(:enable_service).and_return(true)
+    @provider.new_resource.should_receive(:updated=).with(true)
     @provider.action_enable
   end
 
   it &quot;should not enable the service if already enabled&quot; do
     @current_resource.stub!(:enabled).and_return(true)
     @provider.should_not_receive(:enable_service).and_return(true)
+    @provider.new_resource.should_not_receive(:updated=).with(true)
     @provider.action_enable
   end
+
 end
 
 describe Chef::Provider::Service, &quot;action_disable&quot; do
@@ -84,15 +87,17 @@ describe Chef::Provider::Service, &quot;action_disable&quot; do
     @provider.stub!(:disable_service).and_return(true)
   end
 
-  it &quot;should disable the service if enabled&quot; do
+  it &quot;should disable the service if enabled and set the resource as updated&quot; do
     @current_resource.stub!(:enabled).and_return(true)
     @provider.should_receive(:disable_service).and_return(true)
+    @provider.new_resource.should_receive(:updated=).with(true)
     @provider.action_disable
   end
 
   it &quot;should not disable the service if already disabled&quot; do
     @current_resource.stub!(:enabled).and_return(false)
     @provider.should_not_receive(:disable_service).and_return(true)
+    @provider.new_resource.should_not_receive(:updated=).with(true)
     @provider.action_disable
   end
 end
@@ -117,15 +122,17 @@ describe Chef::Provider::Service, &quot;action_start&quot; do
     @provider.stub!(:start_service).and_return(true)
   end
 
-  it &quot;should start the service if it isn't running&quot; do
+  it &quot;should start the service if it isn't running and set the resource as updated&quot; do
     @current_resource.stub!(:running).and_return(false)
     @provider.should_receive(:start_service).with.and_return(true)
+    @provider.new_resource.should_receive(:updated=).with(true)
     @provider.action_start
   end
 
   it &quot;should not start the service if already running&quot; do
     @current_resource.stub!(:running).and_return(true)
     @provider.should_not_receive(:start_service).and_return(true)
+    @provider.new_resource.should_not_receive(:updated=).with(true)
     @provider.action_enable
   end
 end
@@ -150,15 +157,17 @@ describe Chef::Provider::Service, &quot;action_stop&quot; do
     @provider.stub!(:stop_service).and_return(true)
   end
 
-  it &quot;should stop the service if it is running&quot; do
+  it &quot;should stop the service if it is running and set the resource as updated&quot; do
     @current_resource.stub!(:running).and_return(true)
     @provider.should_receive(:stop_service).and_return(true)
+    @provider.new_resource.should_receive(:updated=).with(true)
     @provider.action_stop
   end
 
   it &quot;should not stop the service if it's already stopped&quot; do
     @current_resource.stub!(:running).and_return(false)
     @provider.should_not_receive(:stop_service).and_return(true)
+    @provider.new_resource.should_not_receive(:updated=).with(true)
     @provider.action_stop
   end
 end
@@ -185,14 +194,16 @@ before(:each) do
     @current_resource.stub!(:supports).and_return({:restart =&gt; true})
   end
 
-  it &quot;should restart the service if it's supported&quot; do
+  it &quot;should restart the service if it's supported and set the resource as updated&quot; do
     @provider.should_receive(:restart_service).and_return(true)
+    @provider.new_resource.should_receive(:updated=).with(true)
     @provider.action_restart
   end
 
-  it &quot;should restart the service even if it isn't running&quot; do
+  it &quot;should restart the service even if it isn't running and set the resource as updated&quot; do
     @current_resource.stub!(:running).and_return(false)
     @provider.should_receive(:restart_service).and_return(true)
+    @provider.new_resource.should_receive(:updated=).with(true)
     @provider.action_restart
   end
 end
@@ -225,15 +236,17 @@ before(:each) do
     lambda { @provider.action_reload }.should raise_error(Chef::Exceptions::UnsupportedAction)
   end
 
-  it &quot;should reload the service if it is running&quot; do
+  it &quot;should reload the service if it is running and set the resource as updated&quot; do
     @current_resource.stub!(:running).and_return(true)
     @provider.should_receive(:reload_service).and_return(true)
+    @provider.new_resource.should_receive(:updated=).with(true)
     @provider.action_reload
   end
 
   it &quot;should not reload the service if it's stopped&quot; do
     @current_resource.stub!(:running).and_return(false)
     @provider.should_not_receive(:stop_service).and_return(true)
+    @provider.new_resource.should_not_receive(:updated=).with(true)
     @provider.action_stop
   end
 end</diff>
      <filename>chef/spec/unit/provider/service_spec.rb</filename>
    </modified>
    <modified>
      <diff>@@ -21,6 +21,7 @@ require File.expand_path(File.join(File.dirname(__FILE__), &quot;..&quot;, &quot;spec_helper&quot;))
 describe Chef::Provider do
   before(:each) do
     @resource = Chef::Resource.new(&quot;funk&quot;)
+    @resource.cookbook_name = &quot;a_delicious_pie&quot;
     @node = Chef::Node.new
     @node.name &quot;latte&quot;
     @provider = Chef::Provider.new(@node, @resource)
@@ -45,4 +46,17 @@ describe Chef::Provider do
   it &quot;should return true for action_nothing&quot; do
     @provider.action_nothing.should eql(true)
   end
+  
+  it &quot;sets @cookbook_name to the cookbook name given by @new_resource&quot; do
+    @provider.instance_variable_get(:@cookbook_name).should == &quot;a_delicious_pie&quot;
+  end
+  
+  it &quot;evals embedded recipes with a pristine resource collection&quot; do
+    @provider.instance_variable_set(:@collection, &quot;bouncyCastle&quot;)
+    temporary_collection = nil
+    snitch = lambda {temporary_collection = @collection}
+    @provider.send(:recipe_eval, &amp;snitch)
+    temporary_collection.should be_an_instance_of(Chef::ResourceCollection)
+    @provider.instance_variable_get(:@collection).should == &quot;bouncyCastle&quot;
+  end
 end
\ No newline at end of file</diff>
      <filename>chef/spec/unit/provider_spec.rb</filename>
    </modified>
    <modified>
      <diff>@@ -78,6 +78,26 @@ describe Chef::Resource::Cron do
     @resource.weekday.should eql(&quot;2&quot;)
   end
 
+  it &quot;should allow you to specify the mailto variable&quot; do
+    @resource.mailto &quot;test@example.com&quot;
+    @resource.mailto.should eql(&quot;test@example.com&quot;)
+  end
+
+  it &quot;should allow you to specify the path&quot; do
+    @resource.path &quot;/usr/bin:/usr/sbin&quot;
+    @resource.path.should eql(&quot;/usr/bin:/usr/sbin&quot;)
+  end
+
+  it &quot;should allow you to specify the home directory&quot; do
+    @resource.home &quot;/root&quot;
+    @resource.home.should eql(&quot;/root&quot;)
+  end
+
+  it &quot;should allow you to specify the shell to run the command with&quot; do
+    @resource.shell &quot;/bin/zsh&quot;
+    @resource.shell.should eql(&quot;/bin/zsh&quot;)
+  end
+
   it &quot;should allow * for all time and date values&quot; do
     [ &quot;minute&quot;, &quot;hour&quot;, &quot;day&quot;, &quot;month&quot;, &quot;weekday&quot; ].each do |x|
       @resource.send(x, &quot;*&quot;).should eql(&quot;*&quot;)</diff>
      <filename>chef/spec/unit/resource/cron_spec.rb</filename>
    </modified>
    <modified>
      <diff>@@ -43,6 +43,10 @@ describe Chef::Resource::Group, &quot;initialize&quot; do
   it &quot;should default members to an empty array&quot; do
     @resource.members.should eql([])
   end
+
+  it &quot;should alias users to members, also an empty array&quot; do
+    @resource.users.should eql([])
+  end
   
   it &quot;should set action to :create&quot; do
     @resource.action.should eql(:create)
@@ -90,18 +94,20 @@ describe Chef::Resource::Group, &quot;members&quot; do
     @resource = Chef::Resource::Group.new(&quot;admin&quot;)
   end
 
-  it &quot;should allow and convert a string&quot; do
-    @resource.members &quot;aj&quot;
-    @resource.members.should eql([&quot;aj&quot;])
-  end
+  [ :users, :members].each do |method|
+    it &quot;(#{method}) should allow and convert a string&quot; do
+      @resource.send(method, &quot;aj&quot;)
+      @resource.send(method).should eql([&quot;aj&quot;])
+    end
 
-  it &quot;should allow an array&quot; do
-    @resource.members [ &quot;aj&quot;, &quot;adam&quot; ]
-    @resource.members.should eql( [&quot;aj&quot;, &quot;adam&quot;] )
-  end
+    it &quot;(#{method}) should allow an array&quot; do
+      @resource.send(method, [ &quot;aj&quot;, &quot;adam&quot; ])
+      @resource.send(method).should eql( [&quot;aj&quot;, &quot;adam&quot;] )
+    end
 
-  it &quot;should not allow a hash&quot; do
-    lambda { @resource.send(:members, { :aj =&gt; &quot;is freakin awesome&quot; }) }.should raise_error(ArgumentError)
+    it &quot;(#{method}) should not allow a hash&quot; do
+      lambda { @resource.send(method, { :aj =&gt; &quot;is freakin awesome&quot; }) }.should raise_error(ArgumentError)
+    end
   end
 end
 </diff>
      <filename>chef/spec/unit/resource/group_spec.rb</filename>
    </modified>
    <modified>
      <diff>@@ -1,6 +1,7 @@
 #
 # Author:: Adam Jacob (&lt;adam@opscode.com&gt;)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
+# Author:: Christopher Walters (&lt;cw@opscode.com&gt;)
+# Copyright:: Copyright (c) 2008, 2009 Opscode, Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the &quot;License&quot;);
@@ -56,6 +57,37 @@ describe Chef::ResourceCollection do
     end
   end
   
+  describe &quot;insert&quot; do 
+    it &quot;should accept only Chef::Resources&quot; do
+      lambda { @rc.insert(@resource) }.should_not raise_error
+      lambda { @rc.insert(&quot;string&quot;) }.should raise_error
+    end
+    
+    it &quot;should append resources to the end of the collection when not executing a run&quot; do
+      zmr = Chef::Resource::ZenMaster.new(&quot;there is no spoon&quot;)
+      @rc.insert(@resource)
+      @rc.insert(zmr)
+      @rc[0].should eql(@resource)
+      @rc[1].should eql(zmr)
+    end
+    
+    it &quot;should insert resources to the middle of the collection if called while executing a run&quot; do
+      resource_to_inject = Chef::Resource::ZenMaster.new(&quot;there is no spoon&quot;)
+      zmr = Chef::Resource::ZenMaster.new(&quot;morpheus&quot;)
+      dummy = Chef::Resource::ZenMaster.new(&quot;keanu reeves&quot;)
+      @rc.insert(zmr)
+      @rc.insert(dummy)
+      
+      @rc.execute_each_resource do |resource|
+        @rc.insert(resource_to_inject) if resource == zmr
+      end
+      
+      @rc[0].should eql(zmr)
+      @rc[1].should eql(resource_to_inject)
+      @rc[2].should eql(dummy)
+    end
+  end
+
   describe &quot;each&quot; do
     it &quot;should allow you to iterate over every resource in the collection&quot; do
       load_up_resources
@@ -204,4 +236,4 @@ describe Chef::ResourceCollection do
     @rc &lt;&lt; Chef::Resource::File.new(&quot;something&quot;)
   end
     
-end
\ No newline at end of file
+end</diff>
      <filename>chef/spec/unit/resource_collection_spec.rb</filename>
    </modified>
    <modified>
      <diff>@@ -18,6 +18,10 @@
 
 require File.expand_path(File.join(File.dirname(__FILE__), &quot;..&quot;, &quot;spec_helper&quot;))
 
+class ResourceTestHarness &lt; Chef::Resource
+  provider_base Chef::Provider::Package
+end
+
 describe Chef::Resource do
   before(:each) do
     @resource = Chef::Resource.new(&quot;funk&quot;)
@@ -164,6 +168,16 @@ describe Chef::Resource do
     end
   end
   
+  describe &quot;to_hash&quot; do
+    it &quot;should convert to a hash&quot; do
+      hash = @resource.to_hash
+      hash.keys.should include( :only_if, :allowed_actions, :params, :provider, 
+                                :updated, :before, :not_if, :supports, :node, 
+                                :actions, :noop, :ignore_failure, :name, :source_line, :action)
+      hash[:name].should eql(&quot;funk&quot;)
+    end
+  end
+  
   describe &quot;self.json_create&quot; do
     it &quot;should deserialize itself from json&quot; do
       json = @resource.to_json
@@ -201,4 +215,16 @@ describe Chef::Resource do
     end
   end
   
+  describe &quot;setting the base provider class for the resource&quot; do
+    
+    it &quot;defaults to Chef::Provider for the base class&quot; do
+      Chef::Resource.provider_base.should == Chef::Provider
+    end
+    
+    it &quot;allows the base provider to be overriden by a &quot; do
+      ResourceTestHarness.provider_base.should == Chef::Provider::Package
+    end
+    
+  end
+  
 end
\ No newline at end of file</diff>
      <filename>chef/spec/unit/resource_spec.rb</filename>
    </modified>
    <modified>
      <diff>@@ -1,4 +1,4 @@
-#
+
 # Author:: Adam Jacob (&lt;adam@opscode.com&gt;)
 # Copyright:: Copyright (c) 2008 Opscode, Inc.
 # License:: Apache License, Version 2.0
@@ -55,7 +55,7 @@ describe Chef::Runner do
   end
   
   it &quot;should pass each resource in the collection to a provider&quot; do
-    @collection.should_receive(:each).once
+    @collection.should_receive(:execute_each_resource).once
     @runner.converge
   end
   
@@ -129,6 +129,21 @@ describe Chef::Runner do
     @runner.converge
   end
   
+  it &quot;should follow a chain of actions&quot; do
+    Chef::Platform.should_receive(:find_provider_for_node).exactly(5).times.and_return(Chef::Provider::SnakeOil)
+    @collection &lt;&lt; Chef::Resource::Cat.new(&quot;peanut&quot;, @collection)
+    @collection[1].notifies :buy, @collection[0], :immediately
+    @collection &lt;&lt; Chef::Resource::Cat.new(&quot;snuffles&quot;, @collection)
+    @collection[2].notifies :purr, @collection[1], :immediately
+    @collection[2].updated = true
+    provider = Chef::Provider::SnakeOil.new(@node, @collection[0])
+    p1 = Chef::Provider::SnakeOil.new(@node, @collection[1])
+    p2 = Chef::Provider::SnakeOil.new(@node, @collection[2])
+    Chef::Provider::SnakeOil.should_receive(:new).exactly(5).times.and_return(provider, p1, p2, p1, provider)   
+    provider.should_receive(:action_buy).once.and_return(true)
+    @runner.converge
+  end
+  
   it &quot;should execute delayed actions on changed resources&quot; do
     Chef::Platform.should_receive(:find_provider_for_node).exactly(3).times.and_return(Chef::Provider::SnakeOil)
     provider = Chef::Provider::SnakeOil.new(@node, @collection[0])
@@ -153,4 +168,4 @@ describe Chef::Runner do
     @runner.converge
   end
 
-end
\ No newline at end of file
+end</diff>
      <filename>chef/spec/unit/runner_spec.rb</filename>
    </modified>
    <modified>
      <diff>@@ -18,6 +18,8 @@ search: --tags search --format pretty -r features/steps -r features/support feat
 language: --tags language --format pretty -r features/steps -r features/support features 
 recipe_inclusion: --tags recipe_inclusion --format pretty -r features/steps -r features/support features 
 provider_remote_file: --tags provider,remote_file --format pretty -r features/steps -r features/support features 
+provider_git: --tags provider,git --format pretty -r features/steps -r features/support features 
 provider_template: --tags template --format pretty -r features/steps -r features/support features
 provider_package_macports: --tags macports --format pretty -r features/steps -r features/support features 
+lwrp: --tags lwrp --format pretty -r features/steps -r features/support features 
 </diff>
      <filename>cucumber.yml</filename>
    </modified>
    <modified>
      <diff>@@ -31,6 +31,10 @@ When /^I run the chef\-client$/ do
   @status = status
 end
 
+When /^I run the chef\-client again$/ do
+  When &quot;I run the chef-client&quot;
+end
+
 When /^I run the chef\-client with '(.+)'$/ do |args|
   @chef_args = args
   When &quot;I run the chef-client&quot;</diff>
      <filename>features/steps/run_client_steps.rb</filename>
    </modified>
  </modified>
  <removed type="array">
    <removed>
      <filename>chef-server-slice/app/controllers/cookbook_attributes.rb</filename>
    </removed>
    <removed>
      <filename>chef-server-slice/app/controllers/cookbook_definitions.rb</filename>
    </removed>
    <removed>
      <filename>chef-server-slice/app/controllers/cookbook_libraries.rb</filename>
    </removed>
    <removed>
      <filename>chef-server-slice/app/controllers/cookbook_recipes.rb</filename>
    </removed>
    <removed>
      <filename>distro/debian/etc/init.d/chef-client</filename>
    </removed>
    <removed>
      <filename>distro/debian/etc/init.d/chef-indexer</filename>
    </removed>
    <removed>
      <filename>distro/debian/etc/init.d/chef-server</filename>
    </removed>
    <removed>
      <filename>distro/debian/man/man1/chef-indexer.1</filename>
    </removed>
    <removed>
      <filename>distro/debian/man/man1/chef-server.1</filename>
    </removed>
    <removed>
      <filename>distro/debian/man/man8/chef-client.8</filename>
    </removed>
    <removed>
      <filename>distro/debian/man/man8/chef-solo.8</filename>
    </removed>
    <removed>
      <filename>distro/redhat/etc/chef/client.rb</filename>
    </removed>
    <removed>
      <filename>distro/redhat/etc/chef/indexer.rb</filename>
    </removed>
    <removed>
      <filename>distro/redhat/etc/chef/server.rb</filename>
    </removed>
    <removed>
      <filename>distro/redhat/etc/init.d/chef-client</filename>
    </removed>
    <removed>
      <filename>distro/redhat/etc/init.d/chef-indexer</filename>
    </removed>
    <removed>
      <filename>distro/redhat/etc/init.d/chef-server</filename>
    </removed>
  </removed>
  <parents type="array">
    <parent>
      <id>e5121817ab8525e51a01a4420631c4829e39b5ae</id>
    </parent>
    <parent>
      <id>6f78b9ff0026b1784375a8baf8076c0cc210c946</id>
    </parent>
  </parents>
  <author>
    <name>Adam Jacob</name>
    <email>adam@opscode.com</email>
  </author>
  <url>http://github.com/opscode/chef/commit/8c2b5381d6819f3e76f2ed58dd9bc8df70408f38</url>
  <id>8c2b5381d6819f3e76f2ed58dd9bc8df70408f38</id>
  <committed-date>2009-10-16T17:00:23-07:00</committed-date>
  <authored-date>2009-10-16T17:00:23-07:00</authored-date>
  <message>Merge branch 'master' of git@github.com:opscode/chef into 0712-merge

Conflicts:

	Rakefile
	chef-server-slice/Rakefile
	chef-server-slice/app/controllers/application.rb
	chef-server-slice/app/controllers/cookbooks.rb
	chef-server-slice/app/views/cookbooks/show.html.haml
	chef-server-slice/lib/chef-server-slice.rb
	chef-server/Rakefile
	chef/Rakefile
	chef/lib/chef.rb
	chef/lib/chef/client.rb
	chef/lib/chef/cookbook.rb
	chef/spec/unit/client_spec.rb
	cucumber.yml</message>
  <tree>e8f517c7d69c78d29e0efd06810b2cdfa2139f90</tree>
  <committer>
    <name>Adam Jacob</name>
    <email>adam@opscode.com</email>
  </committer>
</commit>
