class Autoproj::RepositoryManagers::APT

Apt repository manager class

Constants

AUTOPROJ_SOURCES
INVALID_REPO_MESSAGE
SOURCES_DIR
SOURCE_TYPES

Attributes

autoproj_sources[R]
source_entries[R]
source_files[R]
sources_dir[R]

Public Class Methods

new(ws, sources_dir: SOURCES_DIR, autoproj_sources: AUTOPROJ_SOURCES) click to toggle source
Calls superclass method
# File lib/autoproj/repository_managers/apt.rb, line 20
def initialize(ws, sources_dir: SOURCES_DIR, autoproj_sources: AUTOPROJ_SOURCES)
    @sources_dir = sources_dir
    @autoproj_sources = autoproj_sources
    @source_files = Dir[File.join(sources_dir, "**", "*.list")]
    @source_entries = {}

    source_files.each { |file| load_sources_from_file(file) }
    super(ws)
end

Public Instance Methods

add_apt_key(id, origin, type: :keyserver) click to toggle source
# File lib/autoproj/repository_managers/apt.rb, line 162
def add_apt_key(id, origin, type: :keyserver)
    if type == :keyserver
        Autobuild::Subprocess.run(
            "autoproj",
            "osrepos",
            "sudo",
            "apt-key",
            "adv",
            "--keyserver",
            origin,
            "--recv-key",
            id
        )
    else
        URI(origin).open do |io|
            Autobuild::Subprocess.run(
                "autoproj",
                "osrepos",
                "sudo",
                "apt-key",
                "add",
                "-",
                input_streams: [io]
            )
        end
    end
rescue Errno::ENOENT, SocketError => e
    raise ConfigError, e.message
end
add_entry_to_file(file, entry) click to toggle source
# File lib/autoproj/repository_managers/apt.rb, line 117
def add_entry_to_file(file, entry)
    run_tee_command(["sudo", "tee", "-a", file], entry[:source])
    @source_entries[file] ||= []
    @source_entries[file] << entry
    true
end
add_source(source, file = nil) click to toggle source
# File lib/autoproj/repository_managers/apt.rb, line 75
def add_source(source, file = nil)
    file = if file
               File.join(sources_dir, "sources.list.d", file)
           else
               autoproj_sources
           end

    new_entry = parse_source_line(source)
    found = entry_exist?(new_entry)

    if found
        file = found.first
        entry = found.last
        return false if entry[:enabled]

        enable_entry_in_file(file, entry)
    else
        add_entry_to_file(file, new_entry)
    end
end
append_entry(contents, entry) click to toggle source
# File lib/autoproj/repository_managers/apt.rb, line 96
def append_entry(contents, entry)
    unless entry[:enabled]
        contents << "#"
        contents << " " unless entry[:source].start_with?("#")
    end

    contents << entry[:source]
    contents << "# #{entry[:comment]}" unless entry[:comment].empty?
    contents << "\n"
end
apt_update() click to toggle source
# File lib/autoproj/repository_managers/apt.rb, line 152
def apt_update
    Autobuild::Subprocess.run(
        "autoproj",
        "osrepos",
        "sudo",
        "apt-get",
        "update"
    )
end
enable_entry_in_file(file, enable_entry) click to toggle source
# File lib/autoproj/repository_managers/apt.rb, line 107
def enable_entry_in_file(file, enable_entry)
    contents = ""
    source_entries[file].each do |entry|
        entry[:enabled] = true if enable_entry[:source] == entry[:source]
        append_entry(contents, entry)
    end
    run_tee_command(["sudo", "tee", file], contents)
    true
end
entry_exist?(new_entry) click to toggle source
# File lib/autoproj/repository_managers/apt.rb, line 129
def entry_exist?(new_entry)
    source_entries.each_pair do |file, entries|
        entry = entries.find { |e| e[:source] == new_entry[:source] }
        return [file, entry] if entry
    end
    nil
end
filter_installed_definitions(definitions) click to toggle source
# File lib/autoproj/repository_managers/apt.rb, line 192
def filter_installed_definitions(definitions)
    definitions = definitions.dup.reject do |definition|
        if definition["type"] == "repo"
            _, entry = source_exist?(definition["repo"])
            entry && entry[:enabled]
        else
            key_exist?(definition["id"])
        end
    end
    definitions
end
install(definitions) click to toggle source

rubocop:enable Style/GuardClause

Calls superclass method
# File lib/autoproj/repository_managers/apt.rb, line 307
def install(definitions)
    super
    validate_definitions(definitions)
    definitions = filter_installed_definitions(definitions)
    print_installing_definitions(definitions)

    definitions.each do |definition|
        if definition["type"] == "repo"
            add_source(definition["repo"], definition["file"])
        else
            type = definition["url"] ? "url" : "keyserver"
            origin = definition[type]
            add_apt_key(definition["id"], origin, type: type.to_sym)
        end
    end
    apt_update unless definitions.empty?
end
key_exist?(key) click to toggle source
# File lib/autoproj/repository_managers/apt.rb, line 141
def key_exist?(key)
    exist = false
    Open3.popen3({ "LANG" => "C" }, "apt-key", "export", key) do |_, _, stderr, wait_thr|
        success = wait_thr.value.success?
        stderr = stderr.read
        has_error = stderr.match(/WARNING: nothing exported/)
        exist = success && !has_error
    end
    exist
end
load_sources_from_file(file) click to toggle source
# File lib/autoproj/repository_managers/apt.rb, line 34
def load_sources_from_file(file)
    contents = File.open(file).read
    contents.gsub!(/\r\n?/, "\n")

    contents.each_line do |line|
        @source_entries[file] ||= []
        @source_entries[file] << parse_source_line(line, raise_if_invalid: false)
    end
end
os_dependencies() click to toggle source
Calls superclass method
# File lib/autoproj/repository_managers/apt.rb, line 30
def os_dependencies
    super + %w[archive-keyring gnupg apt-transport-https]
end
parse_source_line(line, raise_if_invalid: true) click to toggle source
# File lib/autoproj/repository_managers/apt.rb, line 44
def parse_source_line(line, raise_if_invalid: true)
    entry = {}
    entry[:valid] = false
    entry[:enabled] = true
    entry[:source] = ""
    entry[:comment] = ""

    line.strip!
    if line.start_with?("#")
        entry[:enabled] = false
        line = line[1..-1]
    end

    i = line.index("#")
    if i&.positive?
        entry[:comment] = line[(i + 1)..-1].strip
        line = line[0..(i - 1)]
    end

    entry[:source] = line.strip
    chunks = entry[:source].split
    entry[:valid] = true if SOURCE_TYPES.include?(chunks[0])
    entry[:source] = chunks.join(" ")

    if raise_if_invalid && (!entry[:valid] || !entry[:enabled])
        raise ConfigError, "Invalid source line: #{entry[:source]}"
    end

    entry
end
print_installing_definitions(definitions) click to toggle source
run_tee_command(command, contents) click to toggle source
# File lib/autoproj/repository_managers/apt.rb, line 124
def run_tee_command(command, contents)
    contents = StringIO.new("#{contents}\n")
    Autobuild::Subprocess.run("autoproj", "osrepos", *command, input_streams: [contents])
end
source_exist?(source) click to toggle source
# File lib/autoproj/repository_managers/apt.rb, line 137
def source_exist?(source)
    entry_exist?(parse_source_line(source))
end
validate_definitions(definitions) click to toggle source

Validates repositories definitions from .osrepos files

Examples:

  • ubuntu:

  • ubuntu:

    • xenial: type: key id: 630239CC130E1A7FD81A27B140976EAF437D05B5 keyserver: ‘hkp://ha.pool.sks-keyservers.net:80’

  • ubuntu:

# File lib/autoproj/repository_managers/apt.rb, line 251
def validate_definitions(definitions)
    definitions.each do |definition|
        case definition["type"]
        when "repo"
            validate_repo_definition(definition)
        when "key"
            validate_key_definition(definition)
        else
            raise ConfigError,
                  "#{INVALID_REPO_MESSAGE} type: #{definition['type']}"
        end
    end
end
validate_key_definition(definition) click to toggle source
# File lib/autoproj/repository_managers/apt.rb, line 287
def validate_key_definition(definition)
    if definition["id"].nil?
        raise ConfigError, "#{INVALID_REPO_MESSAGE}: 'id' key missing"
    elsif !definition["id"].is_a?(String)
        raise ConfigError, "#{INVALID_REPO_MESSAGE}: 'id' should be a String"
    elsif definition["url"] && definition["keyserver"]
        raise ConfigError,
              "#{INVALID_REPO_MESSAGE}: 'url' conflicts with 'keyserver'"
    elsif definition["url"] && !definition["url"].is_a?(String)
        raise ConfigError, "#{INVALID_REPO_MESSAGE}: 'url' should be a String"
    elsif definition["keyserver"] && !definition["keyserver"].is_a?(String)
        raise ConfigError,
              "#{INVALID_REPO_MESSAGE}: 'keyserver' should be a String"
    end

    nil
end
validate_repo_definition(definition) click to toggle source

rubocop:disable Style/GuardClause

# File lib/autoproj/repository_managers/apt.rb, line 269
def validate_repo_definition(definition)
    if definition["repo"].nil?
        raise ConfigError, "#{INVALID_REPO_MESSAGE}: 'repo' key missing"
    elsif !definition["repo"].is_a?(String)
        raise ConfigError,
              "#{INVALID_REPO_MESSAGE}: 'repo' should be a String"
    elsif definition["file"] && !definition["file"].is_a?(String)
        raise ConfigError,
              "#{INVALID_REPO_MESSAGE}: 'file' should be a String"
    elsif definition["file"] && Pathname.new(definition["file"]).absolute?
        raise ConfigError,
              "#{INVALID_REPO_MESSAGE}: 'file' should be relative "\
              "to #{File.join(SOURCES_DIR, 'sources.list.d')}"
    end

    nil
end