class Chef::Provider::Package::Dnf::PythonHelper

Constants

DNF_HELPER

Attributes

stderr[RW]
stdin[RW]
stdout[RW]
wait_thr[RW]

Public Instance Methods

check() click to toggle source
# File lib/chef/provider/package/dnf/python_helper.rb, line 60
def check
  start if stdin.nil?
end
compare_versions(version1, version2) click to toggle source
# File lib/chef/provider/package/dnf/python_helper.rb, line 64
def compare_versions(version1, version2)
  with_helper do
    json = build_version_query("versioncompare", [version1, version2])
    Chef::Log.trace "sending '#{json}' to python helper"
    stdin.syswrite json + "\n"
    stdout.sysread(4096).chomp.to_i
  end
end
dnf_command() click to toggle source
# File lib/chef/provider/package/dnf/python_helper.rb, line 39
def dnf_command
  @dnf_command ||= which("python", "python3", "python2", "python2.7") do |f|
    shell_out("#{f} -c 'import dnf'").exitstatus == 0
  end + " #{DNF_HELPER}"
end
query(action, provides, version = nil, arch = nil) click to toggle source

@returns Array<Version>

# File lib/chef/provider/package/dnf/python_helper.rb, line 74
def query(action, provides, version = nil, arch = nil)
  with_helper do
    json = build_query(action, provides, version, arch)
    Chef::Log.trace "sending '#{json}' to python helper"
    stdin.syswrite json + "\n"
    output = stdout.sysread(4096).chomp
    Chef::Log.trace "got '#{output}' from python helper"
    version = parse_response(output)
    Chef::Log.trace "parsed #{version} from python helper"
    version
  end
end
reap() click to toggle source
# File lib/chef/provider/package/dnf/python_helper.rb, line 50
def reap
  unless wait_thr.nil?
    Process.kill("KILL", wait_thr.pid) rescue nil
    stdin.close unless stdin.nil?
    stdout.close unless stdout.nil?
    stderr.close unless stderr.nil?
    wait_thr.value # this calls waitpit()
  end
end
restart() click to toggle source
# File lib/chef/provider/package/dnf/python_helper.rb, line 87
def restart
  reap
  start
end
start() click to toggle source
# File lib/chef/provider/package/dnf/python_helper.rb, line 45
def start
  ENV["PYTHONUNBUFFERED"] = "1"
  @stdin, @stdout, @stderr, @wait_thr = Open3.popen3(dnf_command)
end

Private Instance Methods

add_version(hash, version) click to toggle source

i couldn't figure out how to decompose an evr on the python side, it seems reasonably painless to do it in ruby (generally massaging nevras in the ruby side is HIGHLY discouraged – this is an “every rule has an exception” exception – any additional functionality should probably trigger moving this regexp logic into python)

# File lib/chef/provider/package/dnf/python_helper.rb, line 98
def add_version(hash, version)
  epoch = nil
  if version =~ /(\S+):(\S+)/
    epoch = $1
    version = $2
  end
  if version =~ /(\S+)-(\S+)/
    version = $1
    release = $2
  end
  hash["epoch"] = epoch unless epoch.nil?
  hash["release"] = release unless release.nil?
  hash["version"] = version
end
build_query(action, provides, version, arch) click to toggle source
# File lib/chef/provider/package/dnf/python_helper.rb, line 113
def build_query(action, provides, version, arch)
  hash = { "action" => action }
  hash["provides"] = provides
  add_version(hash, version) unless version.nil?
  hash["arch" ] = arch unless arch.nil?
  FFI_Yajl::Encoder.encode(hash)
end
build_version_query(action, versions) click to toggle source
# File lib/chef/provider/package/dnf/python_helper.rb, line 121
def build_version_query(action, versions)
  hash = { "action" => action }
  hash["versions"] = versions
  FFI_Yajl::Encoder.encode(hash)
end
drain_stderr() click to toggle source
# File lib/chef/provider/package/dnf/python_helper.rb, line 132
def drain_stderr
  output = ""
  until IO.select([stderr], nil, nil, 0).nil?
    output += stderr.sysread(4096).chomp
  end
  output
rescue
  # we must rescue EOFError, and we don't much care about errors on stderr anyway
  output
end
parse_response(output) click to toggle source
# File lib/chef/provider/package/dnf/python_helper.rb, line 127
def parse_response(output)
  array = output.split.map { |x| x == "nil" ? nil : x }
  array.each_slice(3).map { |x| Version.new(*x) }.first
end
with_helper() { || ... } click to toggle source
# File lib/chef/provider/package/dnf/python_helper.rb, line 143
def with_helper
  max_retries ||= 5
  ret = nil
  Timeout.timeout(600) do
    check
    ret = yield
  end
  output = drain_stderr
  unless output.empty?
    Chef::Log.trace "discarding output on stderr from python helper: #{output}"
  end
  ret
rescue EOFError, Errno::EPIPE, Timeout::Error, Errno::ESRCH => e
  output = drain_stderr
  if ( max_retries -= 1 ) > 0
    unless output.empty?
      Chef::Log.trace "discarding output on stderr from python helper: #{output}"
    end
    restart
    retry
  else
    raise e if output.empty?
    raise "dnf-helper.py had stderr output:\n\n#{output}"
  end
end