class Autoproj::OSPackageInstaller

Constants

HANDLE_ALL
HANDLE_NONE
HANDLE_OS
HANDLE_RUBY
PACKAGE_MANAGERS

Attributes

force_osdeps[RW]
filter_uptodate_packages[W]

If set to true (the default), install will try to remove the list of already uptodate packages from the installed packages. Set to false to install all packages regardless of their status

installed_resolved_packages[R]

The set of resolved packages that have already been installed

os_package_resolver[R]
package_managers[R]

Returns the set of package managers

silent[W]
ws[R]

Public Class Methods

new(ws, os_package_resolver, package_managers: PACKAGE_MANAGERS) click to toggle source
# File lib/autoproj/os_package_installer.rb, line 51
def initialize(ws, os_package_resolver, package_managers: PACKAGE_MANAGERS)
    @ws = ws
    @os_package_resolver = os_package_resolver
    @os_package_manager  = nil
    @installed_resolved_packages = Hash.new { |h, k| h[k] = Set.new }
    @silent = true
    @filter_uptodate_packages = true
    @osdeps_mode = nil

    @package_managers = Hash.new
    package_managers.each do |name, klass|
        @package_managers[name] = klass.new(ws)
    end
end

Public Instance Methods

configure_manager() click to toggle source
# File lib/autoproj/os_package_installer.rb, line 200
def configure_manager
    os_package_manager.configure_manager if osdeps_mode.include?("os")
end
define_osdeps_mode_option() click to toggle source
# File lib/autoproj/os_package_installer.rb, line 170
def define_osdeps_mode_option
    if os_package_resolver.supported_operating_system?
        osdeps_mode_option_supported_os(ws.config)
    else
        osdeps_mode_option_unsupported_os(ws.config)
    end
end
each_manager(&block) click to toggle source
# File lib/autoproj/os_package_installer.rb, line 79
def each_manager(&block)
    package_managers.each_value(&block)
end
each_manager_with_name(&block) click to toggle source
# File lib/autoproj/os_package_installer.rb, line 83
def each_manager_with_name(&block)
    package_managers.each(&block)
end
filter_uptodate_packages?() click to toggle source

If set to true (the default), install will try to remove the list of already uptodate packages from the installed packages. Use filter_uptodate_packages= to set it to false to install all packages regardless of their status

# File lib/autoproj/os_package_installer.rb, line 213
def filter_uptodate_packages?
    !!@filter_uptodate_packages
end
install( osdep_packages, all: nil, install_only: false, run_package_managers_without_packages: false, **options ) click to toggle source

Requests the installation of the given set of packages

# File lib/autoproj/os_package_installer.rb, line 423
def install(
    osdep_packages, all: nil, install_only: false,
    run_package_managers_without_packages: false, **options
)
    setup_package_managers(**options)
    partitioned_packages =
        resolve_and_partition_osdep_packages(osdep_packages, all)

    # Install OS packages first, as the other package handlers might
    # depend on OS packages
    if (os_packages = partitioned_packages.delete(os_package_manager))
        install_manager_packages(
            os_package_manager, os_packages,
            install_only: install_only,
            run_package_managers_without_packages:
                run_package_managers_without_packages
        )
    end
    partitioned_packages.each do |manager, package_list|
        install_manager_packages(
            manager, package_list,
            install_only: install_only,
            run_package_managers_without_packages:
                run_package_managers_without_packages
        )
    end
end
install_manager_packages(manager, package_list, install_only: false, run_package_managers_without_packages: false) click to toggle source
# File lib/autoproj/os_package_installer.rb, line 451
def install_manager_packages(manager, package_list, install_only: false, run_package_managers_without_packages: false)
    list = package_list.to_set - installed_resolved_packages[manager]

    if !list.empty? || run_package_managers_without_packages
        manager.install(
            list.to_a,
            filter_uptodate_packages: filter_uptodate_packages?,
            install_only: install_only
        )
        installed_resolved_packages[manager].merge(list)
    end
end
os_package_manager() click to toggle source

Returns the package manager object for the current OS

# File lib/autoproj/os_package_installer.rb, line 67
def os_package_manager
    unless @os_package_manager
        name = os_package_resolver.os_package_manager
        @os_package_manager = package_managers[name] ||
                              PackageManagers::UnknownOSManager.new(ws)
    end
    @os_package_manager
end
osdeps_mode() click to toggle source

Returns the osdeps mode chosen by the user

# File lib/autoproj/os_package_installer.rb, line 223
def osdeps_mode
    # This has two uses. It caches the value extracted from the
    # AUTOPROJ_OSDEPS_MODE and/or configuration file. Moreover, it
    # allows to override the osdeps mode by using
    # OSPackageInstaller#osdeps_mode=
    return @osdeps_mode if @osdeps_mode

    config = ws.config
    loop do
        mode =
            if !config.has_value_for?("osdeps_mode") &&
               (mode_name = ENV["AUTOPROJ_OSDEPS_MODE"])
                begin osdeps_mode_string_to_value(mode_name)
                rescue ArgumentError
                    Autoproj.warn "invalid osdeps mode given through "\
                                  "AUTOPROJ_OSDEPS_MODE (#{mode})"
                    nil
                end
            else
                mode_name = config.get("osdeps_mode")
                begin osdeps_mode_string_to_value(mode_name)
                rescue ArgumentError
                    Autoproj.warn "invalid osdeps mode stored "\
                                  "in configuration file"
                    nil
                end
            end

        if mode
            @osdeps_mode = mode
            config.set("osdeps_mode", mode_name, true)
            return mode
        end

        # Invalid configuration values. Retry
        config.reset("osdeps_mode")
        ENV["AUTOPROJ_OSDEPS_MODE"] = nil
    end
end
osdeps_mode=(value) click to toggle source

Override the osdeps mode

# File lib/autoproj/os_package_installer.rb, line 218
def osdeps_mode=(value)
    @osdeps_mode = osdeps_mode_string_to_value(value)
end
osdeps_mode_option_supported_os(config) click to toggle source
# File lib/autoproj/os_package_installer.rb, line 129
        def osdeps_mode_option_supported_os(config)
            long_doc = <<-EOT
The software packages that autoproj will have to build may require other
prepackaged softwares (a.k.a. OS dependencies) to be installed (RubyGems
packages, packages from your operating system/distribution, ...). Autoproj
is able to install those automatically for you.

Advanced users may want to control this behaviour. Additionally, the
installation of some packages require administration rights, which you may
not have. This option is meant to allow you to control autoproj's behaviour
while handling OS dependencies.

* if you say "all", it will install all packages automatically.
  This requires root access thru 'sudo'
* if you say "pip", only the Python packages will be installed.
  Installing these packages does not require root access.
* if you say "gem", only the Ruby packages will be installed.
  Installing these packages does not require root access.
* if you say "os", only the OS-provided packages will be installed.
  Installing these packages requires root access.
* if you say "none", autoproj will not do anything related to the
  OS dependencies.

Finally, you can provide a comma-separated list of pip gem and os.

As any configuration value, the mode can be changed anytime by calling
  autoproj reconfigure

Finally, the "autoproj osdeps" command will give you the necessary information
about the OS packages that you will need to install manually.

So, what do you want ? (all, none or a comma-separated list of: os gem pip)
            EOT
            message = ["Which prepackaged software (a.k.a. 'osdeps') should autoproj install automatically (all, none or a comma-separated list of: os gem pip) ?", long_doc.strip]

            config.declare "osdeps_mode", "string",
                           default: "all",
                           doc: message,
                           lowercase: true
        end
osdeps_mode_option_unsupported_os(config) click to toggle source
# File lib/autoproj/os_package_installer.rb, line 92
        def osdeps_mode_option_unsupported_os(config)
            long_doc = <<-EOT
The software packages that autoproj will have to build may require other
prepackaged softwares (a.k.a. OS dependencies) to be installed (RubyGems
packages, packages from your operating system/distribution, ...). Autoproj is
usually able to install those automatically, but unfortunately your operating
system is not (yet) supported by autoproj's osdeps mechanism, it can only offer
you some limited support.

Some package handlers are cross-platform, and are therefore supported.  However,
you will have to install the kind of OS dependencies (so-called OS packages)

This option is meant to allow you to control autoproj's behaviour while handling
OS dependencies.

* if you say "all", all OS-independent packages are going to be installed.
* if you say "gem", the RubyGem packages will be installed.
* if you say "pip", the Python PIP packages will be installed.
* if you say "none", autoproj will not do anything related to the OS
  dependencies.

As any configuration value, the mode can be changed anytime by calling
  autoproj reconfigure

Finally, the "autoproj osdeps" command will give you the necessary information
about the OS packages that you will need to install manually.

So, what do you want ? (all, none or a comma-separated list of: gem pip)
            EOT
            message = ["Which prepackaged software (a.k.a. 'osdeps') should autoproj install automatically (all, none or a comma-separated list of: gem pip) ?", long_doc.strip]

            config.declare "osdeps_mode", "string",
                           default: "ruby",
                           doc: message,
                           lowercase: true
        end
osdeps_mode_string_to_value(string) click to toggle source
# File lib/autoproj/os_package_installer.rb, line 178
def osdeps_mode_string_to_value(string)
    user_modes = string.to_s.downcase.split(",")
    modes = []
    user_modes.each do |str|
        case str
        when "all"  then modes.concat(%w[os gem pip])
        when "ruby" then modes << "gem"
        when "gem"  then modes << "gem"
        when "pip"  then modes << "pip"
        when "os"   then modes << "os"
        when "none" then # rubocop:disable Lint/EmptyWhen
        else
            if package_managers.key?(str)
                modes << str
            else
                raise ArgumentError, "#{str} is not a known package handler, known handlers are #{package_managers.keys.sort.join(', ')}"
            end
        end
    end
    modes
end
pristine(packages, options = Hash.new) click to toggle source

Requests that packages that are handled within the autoproj project (i.e. gems) are restored to pristine condition

This is usually called as a rebuild step to make sure that all these packages are updated to whatever required the rebuild

# File lib/autoproj/os_package_installer.rb, line 308
def pristine(packages, options = Hash.new)
    install(packages, options.merge(install_only: true))
    packages = os_package_resolver.resolve_os_packages(packages)

    packages = packages.map do |handler_name, list|
        unless (manager = package_managers[handler_name])
            raise ArgumentError, "no package manager called #{handler_name} found"
        end

        [manager, list]
    end

    _, other_packages =
        packages.partition { |handler, list| handler == os_package_manager }
    other_packages.each do |handler, list|
        handler.pristine(list) if handler.respond_to?(:pristine)
    end
end
resolve_and_partition_osdep_packages(osdep_packages, all_osdep_packages = nil) click to toggle source

@api private

Resolves and partitions osdep packages into the various package managers. The returned hash will have one entry per package manager that has a package, with additional entries for package managers that have an empty list but for which {PackageManagers::Manager#call_while_empty?} returns true

@param [Array<String>] osdep_packages the list of osdeps to install @return [Hash<PackageManagers::Manager,Array<(String, String)>] the

resolved and partitioned osdeps

@raise (see resolve_package_managers_in_mapping) @raise [InternalError] if all_osdep_packages is not provided (is nil)

and some strict package managers need to be called to handle
osdep_packages
# File lib/autoproj/os_package_installer.rb, line 363
def resolve_and_partition_osdep_packages(osdep_packages, all_osdep_packages = nil)
    packages = os_package_resolver.resolve_os_packages(osdep_packages)
    packages = resolve_package_managers_in_mapping(packages)
    all_packages = os_package_resolver.resolve_os_packages(all_osdep_packages || Array.new)
    all_packages = resolve_package_managers_in_mapping(all_packages)

    partitioned_packages = Hash.new
    package_managers.each do |manager_name, manager|
        manager_selected = packages.fetch(manager, Set.new).to_set
        manager_all      = all_packages.fetch(manager, Set.new).to_set

        next if manager_selected.empty? && !manager.call_while_empty?

        # If the manager is strict, we need to bypass it if we did not
        # get the complete list of osdep packages
        if manager.strict? && !all_osdep_packages
            unless manager_selected.empty?
                raise InternalError, "requesting to install the osdeps #{partitioned_packages[manager].to_a.sort.join(', ')} through #{manager_name} but the complete list of osdep packages managed by this manager was not provided. This would break the workspace"
            end

            next
        end

        if manager.strict?
            manager_packages = manager_all | manager_selected
        else
            manager_packages = manager_selected
        end

        partitioned_packages[manager] = manager_packages
    end
    resolve_managers_dependencies(partitioned_packages)
end
resolve_managers_dependencies(partitioned_packages) click to toggle source
# File lib/autoproj/os_package_installer.rb, line 397
def resolve_managers_dependencies(partitioned_packages)
    partitioned_packages.clone.each do |manager, packages|
        # Skip if the manager is not being used
        next if packages&.empty?

        manager_dependencies = os_package_resolver.resolve_os_packages(manager.os_dependencies)
        manager_dependencies = resolve_package_managers_in_mapping(manager_dependencies)
        manager_dependencies.each_key do |nested_manager|
            deps = manager_dependencies.fetch(nested_manager, Set.new).to_set
            next if deps.empty?

            unless partitioned_packages[nested_manager]
                partitioned_packages[nested_manager] = Set.new
                enable_recursion = true
            end

            partitioned_packages[nested_manager] += deps
            if enable_recursion
                partitioned_packages = resolve_managers_dependencies(partitioned_packages)
            end
        end
    end
    partitioned_packages
end
resolve_package_managers_in_mapping(mapping) click to toggle source

@api private

Resolves the package managers from their name in a manager-to-package list mapping.

This is a helper method to resolve the value returned by {OSPackageResolver#resolve_os_packages}

@raise [ArgumentError] if a manager name cannot be resolved

# File lib/autoproj/os_package_installer.rb, line 336
def resolve_package_managers_in_mapping(mapping)
    resolved = Hash.new
    mapping.each do |manager_name, package_list|
        unless (manager = package_managers[manager_name])
            raise ArgumentError, "no package manager called #{handler_name} found"
        end

        resolved[manager] = package_list
    end
    resolved
end
setup_package_managers(osdeps_mode: self.osdeps_mode) click to toggle source

Set up the registered package handlers according to the specified osdeps mode

It enables/disables package handlers based on either the value returned by {#osdeps_mode} or the value passed as option (the latter takes precedence). Moreover, sets the handler’s silent flag using {#silent?}

@option options [Array<String>] the package handlers that should be

enabled. The default value is returned by {#osdeps_mode}

@return [Array<PackageManagers::Manager>] the set of enabled package

managers
# File lib/autoproj/os_package_installer.rb, line 274
def setup_package_managers(osdeps_mode: self.osdeps_mode)
    os_package_manager.enabled = false
    package_managers.each_value do |handler|
        handler.enabled = false
    end
    osdeps_mode.each do |m|
        if m == "os"
            os_package_manager.enabled = true
        elsif (pkg = package_managers[m])
            pkg.enabled = true
        else
            available = package_managers.keys.map(&:inspect).sort.join(", ")
            Autoproj.warn "osdep handler #{m.inspect} found in osdep_mode "\
                          "has no handler, available handlers are #{available}"
        end
    end
    os_package_manager.silent = silent?
    package_managers.each_value do |v|
        v.silent = silent?
    end

    enabled_handlers = []
    enabled_handlers << os_package_manager if os_package_manager.enabled?
    package_managers.each_value do |v|
        enabled_handlers << v if v.enabled?
    end
    enabled_handlers
end
silent?() click to toggle source
# File lib/autoproj/os_package_installer.rb, line 43
def silent?
    @silent
end