class Chef::Provider::Package::Dnf

def available_version(index)

@return Array
def available_version(index)
  @available_version ||= []
  @available_version[index] ||= if new_resource.source
                                  resolve_source_to_version_obj
                                else
                                  python_helper.package_query(:whatavailable, package_name_array[index], version: safe_version_array[index], arch: safe_arch_array[index], options: options)
                                end
  @available_version[index]
end

def candidate_version

def candidate_version
  package_name_array.each_with_index.map do |pkg, i|
    available_version(i).version_with_arch
  end
end

def current_version(index)

def current_version(index)
  @current_version ||= []
  @current_version[index] ||= if new_resource.source
                                python_helper.package_query(:whatinstalled, available_version(index).name, arch: safe_arch_array[index], options: options)
                              else
                                python_helper.package_query(:whatinstalled, package_name_array[index], arch: safe_arch_array[index], options: options)
                              end
  @current_version[index]
end

def define_resource_requirements

def define_resource_requirements
  requirements.assert(:install, :upgrade, :remove, :purge) do |a|
    a.assertion { !new_resource.source || ::File.exist?(new_resource.source) }
    a.failure_message Chef::Exceptions::Package, "Package #{new_resource.package_name} not found: #{new_resource.source}"
    a.whyrun "assuming #{new_resource.source} would have previously been created"
  end
  super
end

def dnf(*args)

def dnf(*args)
  shell_out!("dnf", *args)
end

def flushcache

array installs (and the multipackage cookbook) can produce 600% improvements in runtime.
15% hit to the runtime of installing/removing/upgrading packages. correctly using multipackage
cache flushing is accomplished by simply restarting the python helper. this produces a roughly
def flushcache
  python_helper.restart
end

def get_current_versions

def get_current_versions
  package_name_array.each_with_index.map do |pkg, i|
    current_version(i).version_with_arch
  end
end

def install_package(names, versions)

def install_package(names, versions)
  if new_resource.source
    dnf(options, "-y", "install", new_resource.source)
  else
    resolved_names = names.each_with_index.map { |name, i| available_version(i).to_s unless name.nil? }
    dnf(options, "-y", "install", resolved_names)
  end
  flushcache
end

def load_after_resource

def load_after_resource
  # force the installed version array to repopulate
  @current_version = []
  @after_resource = Chef::Resource::DnfPackage.new(new_resource.name)
  after_resource.package_name(new_resource.package_name)
  after_resource.version(get_current_versions)
  after_resource
end

def load_current_resource

def load_current_resource
  flushcache if new_resource.flush_cache[:before]
  @current_resource = Chef::Resource::DnfPackage.new(new_resource.name)
  current_resource.package_name(new_resource.package_name)
  current_resource.version(get_current_versions)
  current_resource
end

def lock_package(names, versions)

support to lock / unlock. The best solution is to write an execute resource which does a not_if `dnf versionlock | grep '^pattern`` kind of approach
NB: the dnf_package provider manages individual single packages, please do not submit issues or PRs to try to add wildcard
def lock_package(names, versions)
  dnf("-d0", "-e0", "-y", options, "versionlock", "add", resolved_package_lock_names(names))
end

def locked_packages

def locked_packages
  @locked_packages ||=
    begin
      locked = dnf("versionlock", "list")
      locked.stdout.each_line.map do |line|
        line.sub(/-[^-]*-[^-]*$/, "").split(":").last.strip
      end
    end
end

def magic_version_array

def magic_version_array
  package_name_array.each_with_index.map do |pkg, i|
    magical_version(i).version_with_arch
  end
end

def magical_version(index)

Returns:
  • (Array) -
def magical_version(index)
  @magical_version ||= []
  @magical_version[index] ||= if new_resource.source
                                python_helper.package_query(:whatinstalled, available_version(index).name, version: safe_version_array[index], arch: safe_arch_array[index], options: options)
                              else
                                python_helper.package_query(:whatinstalled, package_name_array[index], version: safe_version_array[index], arch: safe_arch_array[index], options: options)
                              end
  @magical_version[index]
end

def packages_all_locked?(names, versions)

def packages_all_locked?(names, versions)
  resolved_package_lock_names(names).all? { |n| locked_packages.include? n }
end

def packages_all_unlocked?(names, versions)

def packages_all_unlocked?(names, versions)
  !resolved_package_lock_names(names).any? { |n| locked_packages.include? n }
end

def python_helper


any cached state of installed/available versions and should be kept that way.
python. This class knows nothing about how to compare RPM versions, and does not maintain
remain a lightweight translation layer to translate Chef requests into RPC requests to
about RPMs and what is installed and what is available. The ruby side of this class should
a request to the python side. The python side is then responsible for knowing everything
provider knows only enough to translate Chef-style new_resource name+package+version into
Most of the magic in this class happens in the python helper script. The ruby side of this
def python_helper
  @python_helper ||= PythonHelper.instance
end

def remove_package(names, versions)

def remove_package(names, versions)
  resolved_names = names.each_with_index.map { |name, i| magical_version(i).to_s unless name.nil? }
  dnf(options, "-y", "remove", resolved_names)
  flushcache
end

def resolve_source_to_version_obj

def resolve_source_to_version_obj
  shell_out!("rpm -qp --queryformat '%{NAME} %{EPOCH} %{VERSION} %{RELEASE} %{ARCH}\n' #{new_resource.source}").stdout.each_line do |line|
    # this is another case of committing the sin of doing some lightweight mangling of RPM versions in ruby -- but the output of the rpm command
    # does not match what the yum library accepts.
    case line
      when /^(\S+)\s+(\S+)\s+(\S+)\s+(\S+)\s+(\S+)$/
        return Version.new($1, "#{$2 == "(none)" ? "0" : $2}:#{$3}-#{$4}", $5)
    end
  end
end

def resolved_package_lock_names(names)

this will resolve things like `/usr/bin/perl` or virtual packages like `mysql` -- it will not work (well? at all?) with globs that match multiple packages
def resolved_package_lock_names(names)
  names.each_with_index.map do |name, i|
    unless name.nil?
      if magical_version(i).version.nil?
        available_version(i).name
      else
        magical_version(i).name
      end
    end
  end
end

def safe_arch_array

def safe_arch_array
  if new_resource.arch.is_a?(Array)
    new_resource.arch
  elsif new_resource.arch.nil?
    package_name_array.map { nil }
  else
    [ new_resource.arch ]
  end
end

def safe_version_array

def safe_version_array
  if new_resource.version.is_a?(Array)
    new_resource.version
  elsif new_resource.version.nil?
    package_name_array.map { nil }
  else
    [ new_resource.version ]
  end
end

def unlock_package(names, versions)

support to lock / unlock. The best solution is to write an execute resource which does a only_if `dnf versionlock | grep '^pattern`` kind of approach
NB: the dnf_package provider manages individual single packages, please do not submit issues or PRs to try to add wildcard
def unlock_package(names, versions)
  # dnf versionlock delete on rhel6 needs the glob nonsense in the following command
  dnf("-d0", "-e0", "-y", options, "versionlock", "delete", resolved_package_lock_names(names).map { |n| "*:#{n}-*" })
end

def version_compare(v1, v2)

def version_compare(v1, v2)
  python_helper.compare_versions(v1, v2)
end

def version_equals?(v1, v2)

def version_equals?(v1, v2)
  return false if v1.nil? || v2.nil?
  python_helper.compare_versions(v1, v2) == 0
end

def version_gt?(v1, v2)

def version_gt?(v1, v2)
  return false if v1.nil? || v2.nil?
  python_helper.compare_versions(v1, v2) == 1
end