diff --git a/lib/puppet/provider/package/yum.rb b/lib/puppet/provider/package/yum.rb
index 581a446..d78a705 100755
--- a/lib/puppet/provider/package/yum.rb
+++ b/lib/puppet/provider/package/yum.rb
@@ -104,5 +104,14 @@ Puppet::Type.type(:package).provide :yum, :parent => :rpm, :source => :rpm do
def purge
yum "-y", :erase, @resource[:name]
end
+
+ # Static function that enable multiple package to be install at the same time
+ def self.combine(resource_names)
+
+ # TODO Add lots of test and error handling
+
+ output = yum "-d", "0", "-e", "0", "-y", :install, resource_names
+
+ end
end

diff --git a/lib/puppet/transaction.rb b/lib/puppet/transaction.rb
index 37f51b2..4ba0ecc 100644
--- a/lib/puppet/transaction.rb
+++ b/lib/puppet/transaction.rb
@@ -219,7 +219,11 @@ class Transaction

# Perform the actual changes
seconds = thinmark do
- events += apply(resource)
+ if combineable?(resource)
+ events += combine(resource)
+ else
+ events += apply(resource)
+ end
end

if children and ! resource.depthfirst?
@@ -473,7 +477,101 @@ class Transaction
end
end
end
+
+ # Test if a specific resource can be combined, only package resources can be combined so far
+ #
+ # Retrun true if it can be combined false otherwise
+ # * its provider should support combine
+ # * it should not be skiped
+ # * the combine attribute should be set to true
+ # * puppet is not running on noop mode
+ # * the packet is ensure (present, latest or installed), version is not supported for multiple install yet.
+ def combineable?(resource)
+ if resource.provider.class.respond_to?(:combine) and
+ ! resource.noop and
+ ! skip?(resource) and
+ resource[:combine] == :true and
+ [:present,:latest,:installed].include?(resource[:ensure]) and
+ changes = resource.evaluate and
+ allow_processing?(resource,changes) and
+ ! changes.empty?
+ puts resource.to_yaml
+ return true
+ else
+ return false
+ end
+ end
+
+ # Function that install all the package available of the same class in a single package manager call if it is possible to combine them.
+ def combine(resource)
+
+ provider_class = resource.provider.class
+
+ @multiple_install_events ||= {}
+ @multiple_install_events[provider_class] ||= {}
+
+ if events = @multiple_install_events[provider_class][resource.name]
+ return events
+ end
+
+ # Find all resources matching the provider class that set combining
+ resources = catalog.vertices.reject { |r|
+
+ !r.provider.class.equal?(provider_class) or !combineable?(r)
+
+ # All the resource that will be installed
+ }.collect { |r|
+
+ changes = r.evaluate
+ changes = [changes] unless changes.is_a?(Array)
+
+ if changes.length > 0
+ @resourcemetrics[:out_of_sync] += 1
+ end
+
+ changes.each { |c|
+ @changes << c
+ @count += 1
+ }
+
+ resourceevents = [Puppet::Transaction::Event.new(r.name, r)]
+
+ # Record when we last synced
+ r.cache(:synced, Time.now)

+ # Flush, if appropriate
+ if r.respond_to?(:flush)
+ r.flush
+ end
+
+ # And set a trigger for refreshing this resource if it's a
+ # self-refresher
+ if r.self_refresh? and ! r.deleting?
+ # Create an edge with this resource as both the source and
+ # target. The triggering method treats these specially for
+ # logging.
+ events = resourceevents.collect { |e| e.name }
+ set_trigger(Puppet::Relationship.new(r,r, :callback => :refresh, :event => events))
+ end
+
+ @multiple_install_events[provider_class][r.name] = resourceevents
+
+ r
+ }
+
+ # collecting their names in an array
+ resource_names = resources.collect { |r|
+ r[:name]
+ }
+
+ # Add error handling ...
+ if resource_names.length > 0
+ output = provider_class.combine(resource_names)
+ end
+
+ @multiple_install_events[provider_class][resource.name]
+ end
+
# Prepare to evaluate the resources in a transaction.
def prepare
# Now add any dynamically generated resources
diff --git a/lib/puppet/type/package.rb b/lib/puppet/type/package.rb
index 655f9e0..2c507ed 100644
--- a/lib/puppet/type/package.rb
+++ b/lib/puppet/type/package.rb
@@ -277,6 +277,14 @@ module Puppet
newvalues(:true, :false)
end

+ newparam(:combine) do
+ desc "Tells package provider if the packet installation have to be
+ perform in a single call by the packet manager or if it has to
+ be executed alone."
+ defaultto :false
+ newvalues(:true, :false)
+ end
+
autorequire(:file) do
autos = []
[:responsefile, :adminfile].each { |param|