class Autoproj::OSPackageResolver

Manager for packages provided by external package managers

Constants

AUTOPROJ_OSDEPS
AVAILABLE

Value returned by availability_of if the required package is available

FOUND_NONEXISTENT

Value returned by resolve_package and partition_osdep_entry in the status field. See the documentation of these methods for more information

FOUND_PACKAGES

Value returned by resolve_package and partition_osdep_entry in the status field. See the documentation of these methods for more information

IGNORE

Value returned by availability_of if the required package is available, but no package needs to be installed to have it

NONEXISTENT

Value returned by availability_of if the required package has definitions, but the nonexistent keyword was used for this OS

NO_PACKAGE

Value returned by availability_of if the required package has no definition

OS_PACKAGE_MANAGERS

Mapping from OS name to package manager name

Package handlers and OSes MUST have different names. The former are used to resolve packages and the latter to resolve OSes in the osdeps. Since one can force the use of a package manager in any OS by adding a package manager entry, as e.g.

ubuntu:

homebrew: package

we need to be able to separate between OS and package manager names.

PACKAGE_MANAGERS
UNKNOWN_OS

Value returned by availability_of if the required package has definitions, but the local OS is unknown

WRONG_OS

Value returned by availability_of if the required package has definitions, but not for this OS name or version

Attributes

aliases[R]

Aliases for osdep packages

all_definitions[R]

All the information contained in all the OSdeps files, as a mapping from the OSdeps package name to [osdeps_file, definition] pairs

definitions[R]

The information contained in the OSdeps files, as a hash

package_managers[R]

Returns the set of known package managers

@return [Array<String>]

prefer_indep_over_os_packages[W]
resolve_package_cache[R]

Cached results of {#resolve_package}

sources[R]

The information as to from which osdeps file the current package information in definitions originates. It is a mapping from the package name to the osdeps file’ full path

ws[R]

The underlying workspace

Public Class Methods

autodetect_operating_system() click to toggle source

Autodetects the operating system name and version

osname is the operating system name, all in lowercase (e.g. ubuntu, arch, gentoo, debian)

versions is a set of names that describe the OS version. It includes both the version number (as a string) and/or the codename if there is one.

Examples: [‘debian’, [‘sid’, ‘unstable’]] or [‘ubuntu’, [‘lucid lynx’, ‘10.04’]]

# File lib/autoproj/os_package_resolver.rb, line 421
def self.autodetect_operating_system
    if (user_os = ENV["AUTOPROJ_OS"])
        if user_os.empty?
            return false
        else
            names, versions = user_os.split(":")
            return normalize_os_representation(
                names.split(","), versions.split(",")
            )
        end
    end

    names, versions = os_from_os_release
    names, versions = guess_operating_system unless names

    # on Debian, they refuse to put enough information to detect
    # 'unstable' reliably. So, we use the heuristic method for it
    if names[0] == "debian"
        # check if we actually got a debian with the "unstable" (sid)
        # flavour. it seems that "/etc/debian_version" does not contain
        # "sid" (but "8.0" for example) during the feature freeze
        # phase...
        if File.exist?("/etc/debian_version")
            debian_versions = [File.read("/etc/debian_version").strip]
            versions = %w[unstable sid] if debian_versions.first =~ /sid/
        end
        # otherwise "versions" contains the result it previously had
    end
    return unless names

    names = ensure_derivatives_refer_to_their_parents(names)
    names, versions = normalize_os_representation(names, versions)
    [names, versions]
end
autodetect_ruby_program() click to toggle source
# File lib/autoproj/os_package_resolver.rb, line 43
def self.autodetect_ruby_program
    ruby = RbConfig::CONFIG["RUBY_INSTALL_NAME"]
    ruby_bindir = RbConfig::CONFIG["bindir"]
    ruby_executable = File.join(ruby_bindir, ruby)
    Autobuild.programs["ruby"] = ruby_executable
    ruby_executable
end
ensure_derivatives_refer_to_their_parents(names) click to toggle source
# File lib/autoproj/os_package_resolver.rb, line 374
def self.ensure_derivatives_refer_to_their_parents(names)
    names = names.dup
    version_files = Hash[
        "/etc/debian_version" => "debian",
        "/etc/redhat-release" => "fedora",
        "/etc/gentoo-release" => "gentoo",
        "/etc/arch-release" => "arch",
        "/etc/SuSE-release" => "opensuse"]
    version_files.each do |file, name|
        names << name if File.exist?(file) && !names.include?(name)
    end
    names
end
guess_operating_system() click to toggle source
# File lib/autoproj/os_package_resolver.rb, line 323
def self.guess_operating_system
    if File.exist?("/etc/debian_version")
        versions = [File.read("/etc/debian_version").strip]
        versions = %w[unstable sid] if versions.first =~ /sid/
        [["debian"], versions]
    elsif File.exist?("/etc/redhat-release")
        release_string = File.read("/etc/redhat-release").strip
        release_string =~ /(.*) release ([\d.]+)/
        name = $1.downcase
        version = $2
        name = "rhel" if name =~ /Red Hat Entreprise/
        [[name], [version]]
    elsif File.exist?("/etc/gentoo-release")
        release_string = File.read("/etc/gentoo-release").strip
        release_string =~ /^.*([^\s]+)$/
        version = $1
        [["gentoo"], [version]]
    elsif File.exist?("/etc/arch-release")
        [["arch"], []]
    elsif Autobuild.macos?
        version = `sw_vers | head -2 | tail -1`.split(":")[1]
        manager =
            ENV["AUTOPROJ_MACOSX_PACKAGE_MANAGER"] ||
            "macos-brew"
        unless OS_PACKAGE_MANAGERS.key?(manager)
            known_managers = OS_PACKAGE_MANAGERS.keys.grep(/^macos/)
            raise ArgumentError, "#{manager} is not a known MacOSX "\
                                 "package manager. Known package managers are "\
                                 "#{known_managers.join(', ')}"
        end

        managers =
            if manager == "macos-port"
                [manager, "port"]
            else
                [manager]
            end
        [[*managers, "darwin"], [version.strip]]
    elsif Autobuild.windows?
        [["windows"], []]
    elsif File.exist?("/etc/SuSE-release")
        version = File.read("/etc/SuSE-release").strip
        version =~ /.*VERSION\s+=\s+([^\s]+)/
        version = $1
        [["opensuse"], [version.strip]]
    elsif Autobuild.freebsd?
        version = `uname -r`.strip.split("-")[0]
        [["freebsd"], [version]]
    end
end
load(file, suffixes: [], **options) click to toggle source
# File lib/autoproj/os_package_resolver.rb, line 7
def self.load(file, suffixes: [], **options)
    unless File.file?(file)
        raise ArgumentError, "no such file or directory #{file}"
    end

    candidates = [file]
    candidates.concat(suffixes.map { |s| "#{file}-#{s}" })

    error_t =
        if defined? Psych::SyntaxError
            [ArgumentError, Psych::SyntaxError]
        else
            ArgumentError
        end

    result = new(**options)
    candidates.each do |file_candidate|
        next unless File.file?(file_candidate)

        file_candidate = File.expand_path(file_candidate)
        begin
            data = YAML.safe_load(File.read(file_candidate)) || Hash.new
            verify_definitions(data)
        rescue *error_t => e
            raise ConfigError.new, "error in #{file_candidate}: "\
                                   "#{e.message}", e.backtrace
        end

        result.merge(new(data, file_candidate, **options))
    end
    result
end
load_default() click to toggle source
# File lib/autoproj/os_package_resolver.rb, line 52
def self.load_default
    file = ENV["AUTOPROJ_DEFAULT_OSDEPS"] || AUTOPROJ_OSDEPS
    unless File.file?(file)
        Autoproj.warn "#{file} (from AUTOPROJ_DEFAULT_OSDEPS) is not a file, "\
                      "falling back to #{AUTOPROJ_OSDEPS}"
        file = AUTOPROJ_OSDEPS
    end
    load(file)
end
new(defs = Hash.new, file = nil, operating_system: nil, package_managers: PACKAGE_MANAGERS.dup, os_package_manager: nil) click to toggle source

The Gem::SpecFetcher object that should be used to query RubyGems, and install RubyGems packages

# File lib/autoproj/os_package_resolver.rb, line 143
def initialize(defs = Hash.new, file = nil,
    operating_system: nil,
    package_managers: PACKAGE_MANAGERS.dup,
    os_package_manager: nil)
    @definitions = defs.to_hash
    @resolve_package_cache = Hash.new
    @all_definitions = Hash.new { |h, k| h[k] = Array.new }
    @package_managers = package_managers
    self.os_package_manager = os_package_manager

    @prefer_indep_over_os_packages = false
    @aliases = Hash.new

    @sources = Hash.new
    @installed_packages = Set.new
    @operating_system = operating_system
    @supported_operating_system = nil
    @odeps_mode = nil
    if file
        defs.each_key do |package_name|
            sources[package_name] = file
            all_definitions[package_name] << [[file], defs[package_name]]
        end
    else
        defs.each_key do |package_name|
            all_definitions[package_name] << [[], defs[package_name]]
        end
    end
end
normalize_os_representation(names, versions) click to toggle source
# File lib/autoproj/os_package_resolver.rb, line 388
def self.normalize_os_representation(names, versions)
    # Normalize the names to lowercase
    names    = names.map(&:downcase)
    versions = versions.map(&:downcase)
    versions += ["default"] unless versions.include?("default")
    [names, versions]
end
os_from_lsb() click to toggle source
# File lib/autoproj/os_package_resolver.rb, line 479
def self.os_from_lsb
    return unless Autobuild.find_in_path("lsb_release")

    distributor = [`lsb_release -i -s`.strip.downcase]
    codename    = `lsb_release -c -s`.strip.downcase
    version     = `lsb_release -r -s`.strip.downcase

    [distributor, [codename, version]]
end
os_from_os_release(filename = "/etc/os-release") click to toggle source
# File lib/autoproj/os_package_resolver.rb, line 456
def self.os_from_os_release(filename = "/etc/os-release")
    return unless File.exist?(filename)

    fields = Hash.new
    File.readlines(filename).each do |line|
        line = line.strip
        if line.strip =~ /^(\w+)=(?:["'])?([^"']+)(?:["'])?$/
            fields[$1] = $2
        elsif !line.empty?
            Autoproj.warn "could not parse line '#{line.inspect}' "\
                          "in /etc/os-release"
        end
    end

    names = []
    versions = []
    names << fields["ID"] << fields["ID_LIKE"]
    versions << fields["VERSION_ID"]
    version = fields["VERSION"] || ""
    versions.concat(version.gsub(/[^\w.]/, " ").split(" "))
    [names.compact.uniq, versions.compact.uniq]
end
verify_definitions(hash, path = []) click to toggle source

Perform some sanity checks on the given osdeps definitions

# File lib/autoproj/os_package_resolver.rb, line 272
def self.verify_definitions(hash, path = [])
    hash.each do |key, value|
        if value && !key.kind_of?(String)
            raise ArgumentError,
                  "invalid osdeps definition: found an #{key.class} as a key in "\
                  "#{path.join('/')}. Don't forget to put quotes around numbers"
        elsif !value && key.kind_of?(Hash)
            verify_definitions(key)
        elsif !value && key.kind_of?(Array)
            key.each do |entry|
                next if entry.respond_to?(:to_str)

                if !entry.respond_to?(:to_hash)
                    raise ArgumentError,
                          "invalid osdeps definition: found #{entry} as a value "\
                          "in #{path.join('/')}. Was expecting a string or a hash"
                elsif !entry["name"]
                    raise ArgumentError,
                          "invalid osdeps definition: found #{entry} as a value "\
                          "in #{path.join('/')}. Was expecting a 'name' field."
                end
            end
        end
        next unless value

        if value.kind_of?(Array) || value.kind_of?(Hash)
            verify_definitions(value, (path + [key]))
        elsif !value.kind_of?(String)
            raise ArgumentError,
                  "invalid osdeps definition: found an #{value.class} as a "\
                  "value in #{path.join('/')}. Don't forget to put "\
                  "quotes around numbers"
        end
    end
end

Public Instance Methods

add_aliases(new_aliases) click to toggle source

Register new aliases

@param [String=>String] new_aliases mapping of the alias to the exact

name
# File lib/autoproj/os_package_resolver.rb, line 177
def add_aliases(new_aliases)
    aliases.merge!(new_aliases)
end
add_entries(entries, file: nil) click to toggle source
# File lib/autoproj/os_package_resolver.rb, line 195
def add_entries(entries, file: nil)
    merge(self.class.new(entries, file))
end
all_package_names() click to toggle source

Returns the name of all known OS packages

It includes even the packages for which there are no definitions on this OS

# File lib/autoproj/os_package_resolver.rb, line 185
def all_package_names
    definitions.keys
end
availability_of(name) click to toggle source

If name is an osdeps that is available for this operating system, returns AVAILABLE. Otherwise, returns one of:

NO_PACKAGE

the package has no definitions

WRONG_OS

the package has a definition, but not for this OS

UNKNOWN_OS

the package has a definition, but the local OS is unknown

NONEXISTENT

the package has a definition, but the ‘nonexistent’ keyword was found for this OS

AVAILABLE

the package is available for this OS

IGNORE

the package is available for this OS, but no packages need to be installed for it

# File lib/autoproj/os_package_resolver.rb, line 896
def availability_of(name)
    resolved = resolve_package(name)
    return NO_PACKAGE unless resolved

    if resolved.empty?
        if known_operating_system?
            return WRONG_OS
        else
            return UNKNOWN_OS
        end
    end

    resolved = resolved.find_all do |_, status, list|
        status != FOUND_PACKAGES || !list.empty?
    end
    failed = resolved.find_all do |_, status, _|
        status == FOUND_NONEXISTENT
    end
    if failed.empty?
        if resolved.empty?
            IGNORE
        else
            AVAILABLE
        end
    else
        NONEXISTENT
    end
end
has?(name) click to toggle source

Returns true if name is an acceptable OS package for this OS and version

# File lib/autoproj/os_package_resolver.rb, line 861
def has?(name)
    status = availability_of(name)
    [AVAILABLE, IGNORE].include?(status)
end
include?(name) click to toggle source

Returns true if the given name has an entry in the osdeps

# File lib/autoproj/os_package_resolver.rb, line 855
def include?(name)
    definitions.key?(name)
end
invalidate_resolve_package_cache() click to toggle source
# File lib/autoproj/os_package_resolver.rb, line 199
def invalidate_resolve_package_cache
    @resolve_package_cache.clear
end
known_operating_system?() click to toggle source

Whether the operating system could be autodetected successfully

# File lib/autoproj/os_package_resolver.rb, line 309
def known_operating_system?
    os_names, = operating_system
    !os_names.empty?
end
load_default() click to toggle source
# File lib/autoproj/os_package_resolver.rb, line 62
def load_default
    merge(self.class.load_default)
end
merge(info, suffixes: []) click to toggle source

Merges the osdeps information of info into self. If packages are defined in both OSPackageResolver objects, the information in info takes precedence

# File lib/autoproj/os_package_resolver.rb, line 206
def merge(info, suffixes: [])
    @definitions = definitions.merge(info.definitions) do |h, v1, v2|
        warn_about_merge_collisions(info, suffixes, h, v1, v2) if v1 != v2
        v2
    end
    invalidate_resolve_package_cache

    @sources = sources.merge(info.sources)
    @all_definitions =
        all_definitions
        .merge(info.all_definitions) do |_package_name, all_defs, new_all_defs|
            all_defs = all_defs.dup
            new_all_defs = new_all_defs.dup
            new_all_defs.delete_if do |files, data|
                if (entry = all_defs.find { |_, d| d == data })
                    entry[0] |= files
                end
            end
            all_defs.concat(new_all_defs)
        end
end
operating_system() click to toggle source

The operating system self is targetting

If unset in {#initialize} or by calling {#operating_system=}, it will attempt to autodetect it on the first call

# File lib/autoproj/os_package_resolver.rb, line 400
def operating_system
    @operating_system ||= self.class.autodetect_operating_system
end
operating_system=(values) click to toggle source

Change the operating system this resolver is targetting

# File lib/autoproj/os_package_resolver.rb, line 405
def operating_system=(values)
    @supported_operating_system = nil
    @os_package_manager = nil
    @operating_system = values
end
os_package_manager() click to toggle source

Returns the name of the package manager object for the current OS

@return [String]

# File lib/autoproj/os_package_resolver.rb, line 124
def os_package_manager
    unless @os_package_manager
        os_names, = operating_system
        os_name = os_names.find { |name| OS_PACKAGE_MANAGERS[name] }
        @os_package_manager = OS_PACKAGE_MANAGERS[os_name] || "unknown"
    end
    @os_package_manager
end
os_package_manager=(manager_name) click to toggle source

Use to override the autodetected OS-specific package handler

# File lib/autoproj/os_package_resolver.rb, line 112
def os_package_manager=(manager_name)
    if manager_name && !package_managers.include?(manager_name)
        raise ArgumentError, "#{manager_name} is not a known "\
                             "package manager, known managers are "\
                             "#{package_managers.to_a.sort.join(', ')}"
    end
    @os_package_manager = manager_name
end
partition_osdep_entry(osdep_name, dep_def, handler_names, excluded, *keys) click to toggle source

Helper method that parses the osdep definition to split between the parts needed for this OS and specific package handlers.

osdep_name is the name of the osdep. It is used to resolve explicit mentions of a package handler, i.e. so that:

pkg: gem

is resolved as the ‘pkg’ package to be installed by the ‘gem’ handler

dep_def is the content to parse. It can be a string, array or hash

handler_names is a list of entries that we are looking for. If it is not nil, only entries that explicitely refer to handler_names will be browsed, i.e. in:

pkg:
    - test: 1
    - [a, list, of, packages]

partition_osdep_entry('osdep_name', data, ['test'], [])

will ignore the toplevel list of packages, while

partition_osdep_entry('osdep_name', data, nil, [])

will return it.

excluded is a list of branches that should be ignored during parsing. It is used to e.g. ignore ‘gem’ when browsing for the main OS package list. For instance, in

pkg:
    - test
    - [a, list, of, packages]

partition_osdep_entry('osdep_name', data, nil, ['test'])

the returned value will only include the list of packages (and not ‘test’)

The rest of the arguments are array of strings that contain list of keys to browse for (usually, the OS names and version)

The return value is either nil if no packages were found, or a pair

status, package_list

where status is FOUND_NONEXISTENT if the

nonexistent keyword was found, and FOUND_PACKAGES if either packages or the ignore keyword were found.

# File lib/autoproj/os_package_resolver.rb, line 658
def partition_osdep_entry(osdep_name, dep_def, handler_names, excluded, *keys)
    keys, *additional_keys = *keys
    keys ||= []
    found = false
    nonexistent = false
    result = []
    found_keys = Hash.new
    Array(dep_def).each do |names, values|
        if values
            entry_found, entry_nonexistent, entry_names =
                partition_osdep_map_entry(
                    names, values, osdep_name,
                    handler_names, excluded, keys, found_keys, additional_keys
                )
        else
            entry_found, entry_nonexistent, entry_names =
                partition_osdep_raw_array_entry(
                    names, osdep_name,
                    handler_names, excluded, keys, additional_keys
                )
        end

        found ||= entry_found
        nonexistent ||= entry_nonexistent
        result.concat(entry_names)
    end

    first_entry = found_keys.keys.min
    found_keys = found_keys[first_entry]
    if found_keys
        if found_keys[0] > 0
            nonexistent = true
        else
            found = true
        end
        result.concat(found_keys[1])
    end

    found =
        if nonexistent then FOUND_NONEXISTENT
        elsif found then FOUND_PACKAGES
        else
            false
        end

    [found, result]
end
partition_osdep_map_entry(names, values, osdep_name, handler_names, excluded, keys, found_keys, additional_keys) click to toggle source
# File lib/autoproj/os_package_resolver.rb, line 753
def partition_osdep_map_entry(names, values, osdep_name, handler_names,
    excluded, keys, found_keys, additional_keys)
    # names could be an array already
    names = names.split(",") if names.respond_to?(:to_str)
    result = [false, false, []]

    if handler_names
        matching_handler =
            handler_names.find do |k|
                names.any? { |name_tag| k == name_tag.downcase }
            end

        if matching_handler
            rec_found, rec_result = partition_osdep_entry(
                osdep_name, values, nil, excluded
            )
            if rec_found == FOUND_NONEXISTENT
                result = [false, true, rec_result]
            elsif rec_found == FOUND_PACKAGES
                result = [true, false, rec_result]
            end
        end
    end

    matching_name = keys
                    .find { |k| names.any? { |name_tag| k == name_tag.downcase } }
    return result unless matching_name

    rec_found, rec_result = partition_osdep_entry(
        osdep_name, values, handler_names, excluded, *additional_keys
    )
    # We only consider the first highest-priority entry,
    # regardless of whether it has some packages for us or
    # not
    idx = keys.index(matching_name)
    if rec_found
        found_keys[idx] ||= [0, []]
        found_keys[idx][0] += rec_found
        found_keys[idx][1].concat(rec_result)
    else
        found_keys[idx] = nil unless found_keys.key?(idx)
    end
    result
end
partition_osdep_raw_array_entry(names, osdep_name, handler_names, excluded, keys, additional_keys) click to toggle source
# File lib/autoproj/os_package_resolver.rb, line 706
def partition_osdep_raw_array_entry(names, osdep_name, handler_names,
    excluded, keys, additional_keys)
    have_handler_names = true if handler_names

    # Raw array of packages. Possible only if we are not at toplevel
    # (i.e. if we already have a handler)
    if names == "ignore"
        [!have_handler_names, false, []]
    elsif names == "nonexistent"
        [false, !have_handler_names, []]
    elsif !handler_names && names.kind_of?(Array)
        [true, false, names]
    elsif names.respond_to?(:to_str)
        if excluded.include?(names)
            [false, false, []]
        elsif handler_names&.include?(names)
            [true, false, [osdep_name]]
        elsif !handler_names
            [true, false, [names]]
        else
            [false, false, []]
        end
    elsif names.respond_to?(:to_hash)
        if keys.empty? && additional_keys.empty?
            if excluded.include?(names["name"])
                [false, false, []]
            else
                [true, false, [names]]
            end
        else
            rec_found, rec_result = partition_osdep_entry(
                osdep_name, names, handler_names, excluded,
                keys, *additional_keys
            )
            if rec_found == FOUND_NONEXISTENT
                [false, true, rec_result]
            elsif rec_found == FOUND_PACKAGES
                [true, false, rec_result]
            else
                [false, false, []]
            end
        end
    else
        [false, false, []]
    end
end
prefer_indep_over_os_packages?() click to toggle source

Controls whether the package resolver will prefer installing OS-independent packages (such as e.g. Gems) over their OS-provided equivalent (e.g. the packaged version of a gem)

# File lib/autoproj/os_package_resolver.rb, line 103
def prefer_indep_over_os_packages?
    @prefer_indep_over_os_packages
end
resolve_name(name) click to toggle source

Return the path to the osdeps name for a given package name while accounting for package aliases

returns an array contain the path starting with name and ending at the resolved name

# File lib/autoproj/os_package_resolver.rb, line 496
def resolve_name(name)
    path = [name]
    while aliases.key?(name)
        name = aliases[name]
        path << name
    end
    path
end
resolve_os_packages(dependencies) click to toggle source

Resolves the given OS dependencies into the actual packages that need to be installed on this particular OS.

@param [Array<String>] dependencies the list of osdep names that

should be resolved

@return [Array<#install,Array<String>>] the set of packages, grouped

by the package handlers that should be used to install them

@raise MissingOSDep if some packages can’t be found or if the

nonexistent keyword was found for some of them
# File lib/autoproj/os_package_resolver.rb, line 808
def resolve_os_packages(dependencies)
    all_packages = []
    dependencies.each do |name|
        result = resolve_package(name)
        unless result
            path = resolve_name(name)
            raise MissingOSDep.new,
                  "there is no osdeps definition for #{path.last} "\
                  "(search tree: #{path.join('->')})"
        end

        if result.empty?
            os_names, os_versions = operating_system
            if os_names.empty?
                raise MissingOSDep.new,
                      "there is an osdeps definition for #{name}, but autoproj "\
                      "cannot detect the local operation system"
            else
                raise MissingOSDep.new,
                      "there is an osdeps definition for #{name}, but not for "\
                      "this operating system and version resp. "\
                      "#{os_names.join(', ')} and #{os_versions.join(', ')})"
            end
        end

        result.each do |handler, status, packages|
            if status == FOUND_NONEXISTENT
                raise MissingOSDep.new,
                      "there is an osdep definition for #{name}, and it "\
                      "explicitely states that this package does not exist "\
                      "on your OS"
            end
            if (entry = all_packages.find { |h, _| h == handler })
                entry[1].concat(packages)
            else
                all_packages << [handler, packages.dup]
            end
        end
    end

    all_packages.delete_if do |_handler, pkg|
        pkg.empty?
    end
    all_packages
end
resolve_package(name, resolve_recursive: true) click to toggle source

Return the list of packages that should be installed for name

The following two simple return values are possible:

nil

name has no definition

[]

name has no definition on this OS and/or for this specific OS version

In all other cases, the method returns an array of triples:

[package_handler, status, package_list]

where status is FOUND_PACKAGES if package_list is the list of packages that should be installed with package_handler for name, and FOUND_NONEXISTENT if the nonexistent keyword is used for this OS name and version. The package list might be empty even if status == FOUND_PACKAGES, for instance if the ignore keyword is used.

# File lib/autoproj/os_package_resolver.rb, line 530
def resolve_package(name, resolve_recursive: true)
    return resolve_package_cache[name] if resolve_package_cache.key?(name)

    path = resolve_name(name)
    name = path.last

    dep_def = definitions[name]
    return (resolve_package_cache[name] = nil) unless dep_def

    os_names, os_versions = operating_system

    # Partition the found definition in all entries that are interesting
    # for us: toplevel os-independent package managers, os-dependent
    # package managers and os-independent package managers selected by
    # OS or version
    if os_names.empty?
        os_names = ["default"]
        os_versions = ["default"]
    else
        os_names = os_names.dup
        if prefer_indep_over_os_packages?
            os_names.unshift "default"
        else
            os_names.push "default"
        end
    end

    result = []
    found, pkg = partition_osdep_entry(
        name, dep_def, nil,
        (package_managers - [os_package_manager]), os_names, os_versions
    )
    result << [os_package_manager, found, pkg] if found

    package_managers.each do |handler|
        found, pkg = partition_osdep_entry(
            name, dep_def, [handler], [], os_names, os_versions
        )
        result << [handler, found, pkg] if found
    end

    # Recursive resolutions
    found, pkg = partition_osdep_entry(
        name, dep_def, ["osdep"], [], os_names, os_versions
    )
    if found
        if resolve_recursive
            pkg.each do |pkg_name|
                resolved = resolve_package(pkg_name)
                unless resolved
                    raise InvalidRecursiveStatement,
                          "the '#{name}' osdep refers to another osdep, "\
                          "'#{pkg_name}', which does not seem to exist"
                end
                result.concat(resolved)
            end
        else
            result << [OSDepRecursiveResolver, found, pkg]
        end
    end

    result.each { |args| args.last.freeze }
    result.freeze
    if resolve_recursive
        resolve_package_cache[name] = result
    else
        result
    end
end
source_of(package_name) click to toggle source

Returns the full path to the osdeps file from which the package definition for package_name has been taken

# File lib/autoproj/os_package_resolver.rb, line 191
def source_of(package_name)
    sources[package_name]
end
supported_operating_system?() click to toggle source

Returns true if it is possible to install packages for the operating system on which we are installed

# File lib/autoproj/os_package_resolver.rb, line 316
def supported_operating_system?
    if @supported_operating_system.nil?
        @supported_operating_system = (os_package_manager != "unknown")
    end
    @supported_operating_system
end
warn_about_merge_collisions(merged_info, suffixes, key, _old_value, _new_value) click to toggle source

@api private

Warn about a collision (override) detected during merge

# File lib/autoproj/os_package_resolver.rb, line 231
def warn_about_merge_collisions(merged_info, suffixes, key,
    _old_value, _new_value)
    old = source_of(key)
    new = merged_info.source_of(key)

    return if suffixes.any? { |s| new == "#{old}#{s}" }

    # Warn if the new osdep definition resolves to a different
    # set of packages than the old one
    old_resolved =
        resolve_package(key, resolve_recursive: false)
        .each_with_object(Hash.new) do |(handler, status, list), osdep_h|
            osdep_h[handler] = [status, list.dup]
        end

    new_resolved =
        merged_info
        .resolve_package(key, resolve_recursive: false)
        .each_with_object(Hash.new) do |(handler, status, list), osdep_h|
            osdep_h[handler] = [status, list.dup]
        end

    if old_resolved != new_resolved
        Autoproj.warn "osdeps definition for #{key}, "\
                      "previously defined in #{old} overridden by #{new}:"
        first = true
        old_resolved.each do |handler, (_, packages)|
            Autoproj.warn "  #{first ? 'resp. ' : '      '}#{handler}: "\
                          "#{packages.map(&:to_s).join(', ')}"
            first = false
        end
        first = true
        new_resolved.each do |handler, (_, packages)|
            Autoproj.warn "  #{first ? 'and   ' : '      '}#{handler}: "\
                          "#{packages.map(&:to_s).join(', ')}"
            first = false
        end
    end
end