class PoiseLanguages::System::Provider

The default provider for `poise_languages_system`.

@api private @since 1.0 @see Resource @provides poise_languages_system

Public Instance Methods

action_install() click to toggle source

The `install` action for the `poise_languages_system` resource.

@return [void]

# File lib/poise_languages/system/resource.rb, line 99
def action_install
  notifying_block do
    install_packages
    run_action_hack
  end
end
action_uninstall() click to toggle source

The `uninstall` action for the `poise_languages_system` resource.

@return [void]

# File lib/poise_languages/system/resource.rb, line 119
def action_uninstall
  notifying_block do
    uninstall_packages
  end
end
action_upgrade() click to toggle source

The `upgrade` action for the `poise_languages_system` resource.

@return [void]

# File lib/poise_languages/system/resource.rb, line 109
def action_upgrade
  notifying_block do
    upgrade_packages
    run_action_hack
  end
end

Private Instance Methods

install_packages() click to toggle source

Install the needed language packages.

@api private @return [Array<Chef::Resource>]

# File lib/poise_languages/system/resource.rb, line 131
def install_packages
  packages = {new_resource.package_name => new_resource.package_version}
  # If we are supposed to install the dev package, grab it using the same
  # version as the main package.
  if new_resource.dev_package
    packages[new_resource.dev_package] = new_resource.package_version
  end
  Chef::Log.debug("[#{new_resource.parent}] Building package resource using #{packages.inspect}.")

  # Check for multi-package support.
  package_resource_class = Chef::Resource.resource_for_node(:package, node)
  package_provider_class = package_resource_class.new('multipackage_check', run_context).provider_for_action(:install)
  package_resources = if package_provider_class.respond_to?(:use_multipackage_api?) && package_provider_class.use_multipackage_api?
    package packages.keys do
      version packages.values
    end
  else
    # Fallback for non-multipackage.
    packages.map do |pkg_name, pkg_version|
      package pkg_name do
        version pkg_version
      end
    end
  end

  # Apply some settings to all of the resources.
  Array(package_resources).each do |res|
    res.retries(5)
    res.define_singleton_method(:apply_action_hack?) { true }
  end
end
patch_load_current_resource!(provider, version) click to toggle source

Hack a provider object to run our verification code.

@param provider [Chef::Provider] Provider object to patch. @param version [String] Language version prefix to check for. @return [void]

# File lib/poise_languages/system/resource.rb, line 226
def patch_load_current_resource!(provider, version)
  # Create a closure module and inject it.
  provider.extend Module.new {
    # Patch load_current_resource to run our verification logic after
    # the normal code.
    define_method(:load_current_resource) do
      super().tap do |_|
        each_package do |package_name, new_version, current_version, candidate_version|
          # In Chef 12.14+, candidate_version is a Chef::Decorator::Lazy object
          # so we need the nil? check to see if the object being proxied is
          # nil (i.e. there is no version). The `\d+:` is for RPM epoch prefixes.
          unless candidate_version && (!candidate_version.nil?) && (!candidate_version.empty?) && candidate_version =~ /^(\d+:)?#{Regexp.escape(version)}/
            # Don't display a wonky error message if there is no candidate.
            candidate_label = if candidate_version && (!candidate_version.nil?) && (!candidate_version.empty?)
              candidate_version
            else
              candidate_version.inspect
            end
            raise PoiseLanguages::Error.new("Package #{package_name} would install #{candidate_label}, which does not match #{version.empty? ? version.inspect : version}. Please set the package_name or package_version provider options.")
          end
        end
      end
    end
  }
end
run_action_hack() click to toggle source

Run the requested action for all package resources. This exists because we inject our version check in to the provider directly and I want to only run the provider action once for performance. It is otherwise mostly a stripped down version of Chef::Resource#run_action.

@param action [Symbol] Action to run on all package resources. @return [void]

# File lib/poise_languages/system/resource.rb, line 190
def run_action_hack
  # If new_resource.package_version is set, skip this madness.
  return if new_resource.package_version

  # Process every resource in the current collection, which is bounded
  # by notifying_block.
  run_context.resource_collection.each do |resource|
    # Only apply to things we tagged above.
    next unless resource.respond_to?(:apply_action_hack?) && resource.apply_action_hack?

    Array(resource.action).each do |action|
      # Reset it so we have a clean baseline.
      resource.updated_by_last_action(false)
      # Grab the provider.
      provider = resource.provider_for_action(action)
      provider.action = action
      # Inject our check for the candidate version. This will actually
      # get run during run_action below.
      patch_load_current_resource!(provider, new_resource.version)
      # Run our action.
      Chef::Log.debug("[#{new_resource.parent}] Running #{provider} with #{action}")
      provider.run_action(action)
      # Check updated flag.
      new_resource.updated_by_last_action(true) if resource.updated_by_last_action?
    end

    # Make sure the resource doesn't run again when notifying_block ends.
    resource.action(:nothing)
  end
end
uninstall_packages() click to toggle source

Uninstall the needed language packages.

@api private @return [Array<Chef::Resource>]

# File lib/poise_languages/system/resource.rb, line 177
def uninstall_packages
  install_packages.each do |res|
    res.action(node.platform_family?('debian') ? :purge : :remove)
  end
end
upgrade_packages() click to toggle source

Upgrade the needed language packages.

@api private @return [Array<Chef::Resource>]

# File lib/poise_languages/system/resource.rb, line 167
def upgrade_packages
  install_packages.each do |res|
    res.action(:upgrade)
  end
end