class Chef::Provider::Package::Dpkg

Constants

DPKG_INSTALLED
DPKG_REMOVED
DPKG_VERSION

Public Instance Methods

check_resource_semantics!() click to toggle source

Override the superclass check. Multiple sources are required here.

# File lib/chef/provider/package/dpkg.rb, line 105
def check_resource_semantics!; end
define_resource_requirements() click to toggle source
# File lib/chef/provider/package/dpkg.rb, line 35
def define_resource_requirements
  super

  requirements.assert(:install, :upgrade) do |a|
    a.assertion { !resolved_source_array.compact.empty? }
    a.failure_message Chef::Exceptions::Package, "#{new_resource} the source property is required for action :install or :upgrade"
  end

  requirements.assert(:install, :upgrade) do |a|
    a.assertion { source_files_exist? }
    a.failure_message Chef::Exceptions::Package, "#{new_resource} source file(s) do not exist: #{missing_sources}"
    a.whyrun "Assuming they would have been previously created."
  end
end
install_package(name, version) click to toggle source
# File lib/chef/provider/package/dpkg.rb, line 74
def install_package(name, version)
  sources = name.map { |n| name_sources[n] }
  logger.info("#{new_resource} installing package(s): #{name.join(' ')}")
  run_noninteractive("dpkg", "-i", *options, *sources)
end
load_current_resource() click to toggle source
# File lib/chef/provider/package/dpkg.rb, line 50
def load_current_resource
  @current_resource = Chef::Resource::Package.new(new_resource.name)
  current_resource.package_name(new_resource.package_name)

  if source_files_exist?
    @candidate_version = get_candidate_version
    current_resource.package_name(get_package_name)
    # if the source file exists then our package_name is right
    current_resource.version(get_current_version_from(current_package_name_array))
  elsif !installing?
    # we can't do this if we're installing with no source, because our package_name
    # is probably not right.
    #
    # if we're removing or purging we don't use source, and our package_name must
    # be right so we can do this.
    #
    # we don't error here on the dpkg command since we'll handle the exception or
    # the why-run message in define_resource_requirements.
    current_resource.version(get_current_version_from(current_package_name_array))
  end

  current_resource
end
preseed_package(preseed_file) click to toggle source
# File lib/chef/provider/package/dpkg.rb, line 94
def preseed_package(preseed_file)
  logger.info("#{new_resource} pre-seeding package installation instructions")
  run_noninteractive("debconf-set-selections", *preseed_file)
end
purge_package(name, version) click to toggle source
# File lib/chef/provider/package/dpkg.rb, line 85
def purge_package(name, version)
  logger.info("#{new_resource} purging packages(s): #{name.join(' ')}")
  run_noninteractive("dpkg", "-P", *options, *name)
end
reconfig_package(name, version) click to toggle source
# File lib/chef/provider/package/dpkg.rb, line 99
def reconfig_package(name, version)
  logger.info("#{new_resource} reconfiguring")
  run_noninteractive("dpkg-reconfigure", *name)
end
remove_package(name, version) click to toggle source
# File lib/chef/provider/package/dpkg.rb, line 80
def remove_package(name, version)
  logger.info("#{new_resource} removing package(s): #{name.join(' ')}")
  run_noninteractive("dpkg", "-r", *options, *name)
end
upgrade_package(name, version) click to toggle source
# File lib/chef/provider/package/dpkg.rb, line 90
def upgrade_package(name, version)
  install_package(name, version)
end

Private Instance Methods

current_package_name_array() click to toggle source
# File lib/chef/provider/package/dpkg.rb, line 173
def current_package_name_array
  [ current_resource.package_name ].flatten
end
get_candidate_version() click to toggle source

Return candidate version array from pkg-deb -W against the source file(s).

@return [Array] Array of candidate versions read from the source files

# File lib/chef/provider/package/dpkg.rb, line 219
def get_candidate_version
  package_name_array.map { |name| name_candidate_version[name] }
end
get_current_version_from(array) click to toggle source
# File lib/chef/provider/package/dpkg.rb, line 146
def get_current_version_from(array)
  array.map do |name|
    read_current_version_of_package(name)
  end
end
get_package_name() click to toggle source

Return package names from the candidate source file(s).

@return [Array] Array of actual package names read from the source files

# File lib/chef/provider/package/dpkg.rb, line 226
def get_package_name
  package_name_array.map { |name| name_package_name[name] }
end
installing?() click to toggle source

Since upgrade just calls install, this is a helper to determine if our action means that we'll be calling install_package.

@return [Boolean] true if we're doing :install or :upgrade

# File lib/chef/provider/package/dpkg.rb, line 234
def installing?
  [:install, :upgrade].include?(action)
end
missing_sources() click to toggle source

Helper to return all the nanes of the missing sources for error messages.

@return [Array<String>] Array of missing sources

# File lib/chef/provider/package/dpkg.rb, line 169
def missing_sources
  resolved_source_array.select { |s| s.nil? || !::File.exist?(s) }
end
name_candidate_version() click to toggle source
# File lib/chef/provider/package/dpkg.rb, line 202
def name_candidate_version
  @name_candidate_version ||=
    begin
      Hash[name_pkginfo.map { |k, v| [k, v ? v.split("\t")[1].strip : nil] }]
    end
end
name_package_name() click to toggle source
# File lib/chef/provider/package/dpkg.rb, line 209
def name_package_name
  @name_package_name ||=
    begin
      Hash[name_pkginfo.map { |k, v| [k, v ? v.split("\t")[0] : nil] }]
    end
end
name_pkginfo() click to toggle source

Helper to construct Hash of names-to-package-information.

@return [Hash] Mapping of package names to package information

# File lib/chef/provider/package/dpkg.rb, line 190
def name_pkginfo
  @name_pkginfo ||=
    begin
      pkginfos = resolved_source_array.map do |src|
        logger.trace("#{new_resource} checking #{src} dpkg status")
        status = shell_out_compact_timeout!("dpkg-deb", "-W", src)
        status.stdout
      end
      Hash[*package_name_array.zip(pkginfos).flatten]
    end
end
name_sources() click to toggle source

Helper to construct Hash of names-to-sources.

@return [Hash] Mapping of package names to sources

# File lib/chef/provider/package/dpkg.rb, line 180
def name_sources
  @name_sources =
    begin
      Hash[*package_name_array.zip(resolved_source_array).flatten]
    end
end
read_current_version_of_package(package_name) click to toggle source
# File lib/chef/provider/package/dpkg.rb, line 125
def read_current_version_of_package(package_name)
  logger.trace("#{new_resource} checking install state of #{package_name}")
  status = shell_out_compact_timeout!("dpkg", "-s", package_name, returns: [0, 1])
  package_installed = false
  status.stdout.each_line do |line|
    case line
    when DPKG_REMOVED
      # if we are 'purging' then we consider 'removed' to be 'installed'
      package_installed = true if action == :purge
    when DPKG_INSTALLED
      package_installed = true
    when DPKG_VERSION
      if package_installed
        logger.trace("#{new_resource} current version is #{$1}")
        return $1
      end
    end
  end
  nil
end
run_noninteractive(*command) click to toggle source

Runs command via shell_out_with_timeout with magic environment to disable interactive prompts.

# File lib/chef/provider/package/dpkg.rb, line 154
def run_noninteractive(*command)
  shell_out_compact_timeout!(*command, env: { "DEBIAN_FRONTEND" => "noninteractive" })
end
source_files_exist?() click to toggle source

Returns true if all sources exist. Returns false if any do not, or if no sources were specified.

@return [Boolean] True if all sources exist

# File lib/chef/provider/package/dpkg.rb, line 162
def source_files_exist?
  resolved_source_array.all? { |s| s && ::File.exist?(s) }
end
version_compare(v1, v2) click to toggle source

compare 2 versions to each other to see which is newer. this differs from the standard package method because we need to be able to parse debian version strings which contain tildes which Gem cannot properly parse

@return [Integer] 1 if v1 > v2. 0 if they're equal. -1 if v1 < v2

# File lib/chef/provider/package/dpkg.rb, line 115
def version_compare(v1, v2)
  if !shell_out_compact_timeout("dpkg", "--compare-versions", v1.to_s, "gt", v2.to_s).error?
    1
  elsif !shell_out_compact_timeout("dpkg", "--compare-versions", v1.to_s, "eq", v2.to_s).error?
    0
  else
    -1
  end
end