Class: Autoproj::PackageManagers::AptDpkgManager

Inherits:
ShellScriptManager show all
Defined in:
lib/autoproj/package_managers/apt_dpkg_manager.rb

Overview

Package manager interface for systems that use APT and dpkg for package management

Instance Attribute Summary collapse

Attributes inherited from ShellScriptManager

#auto_install_cmd, #needs_locking, #needs_root, #user_install_cmd

Attributes inherited from Manager

#enabled, #silent, #ws

Class Method Summary collapse

Instance Method Summary collapse

Methods inherited from ShellScriptManager

execute, #generate_auto_os_script, #generate_script, #generate_user_os_script, #needs_locking?, #needs_root?, #osdeps_interaction

Methods inherited from Manager

#call_while_empty?, #enabled?, #initialize_environment, #os_dependencies, #silent?, #strict?

Constructor Details

#initialize(ws, status_file = "/var/lib/dpkg/status") ⇒ AptDpkgManager

Returns a new instance of AptDpkgManager.



18
19
20
21
22
23
24
25
# File 'lib/autoproj/package_managers/apt_dpkg_manager.rb', line 18

def initialize(ws, status_file = "/var/lib/dpkg/status")
    @status_file = status_file
    @installed_packages = nil
    @installed_versions = nil
    super(ws, true,
          %w[apt-get install],
          %w[DEBIAN_FRONTEND=noninteractive apt-get install -y])
end

Instance Attribute Details

#status_fileObject

Returns the value of attribute status_file.



10
11
12
# File 'lib/autoproj/package_managers/apt_dpkg_manager.rb', line 10

def status_file
  @status_file
end

Class Method Details

.inheritObject



13
14
15
# File 'lib/autoproj/package_managers/apt_dpkg_manager.rb', line 13

def inherit
    @inherit ||= Set.new
end

.parse_apt_cache_paragraph(paragraph) ⇒ Object



84
85
86
87
88
89
90
91
92
# File 'lib/autoproj/package_managers/apt_dpkg_manager.rb', line 84

def self.parse_apt_cache_paragraph(paragraph)
    version = "0"
    if (paragraph_m = /^Package: (.*)$/.match(paragraph))
        package_name = paragraph_m[1]
        version_m = /^Version: (.*)$/.match(paragraph)
        version = version_m[1] if version_m
    end
    [package_name, version]
end

.parse_dpkg_status(status_file, virtual: true) ⇒ Object



62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
# File 'lib/autoproj/package_managers/apt_dpkg_manager.rb', line 62

def self.parse_dpkg_status(status_file, virtual: true)
    installed_packages = Set.new
    installed_versions = {}
    dpkg_status = File.read(status_file)
    dpkg_status << "\n"

    dpkg_status = StringScanner.new(dpkg_status)
    unless dpkg_status.scan(/Package: /)
        raise ArgumentError, "expected #{status_file} to have Package: "\
                             "lines but found none"
    end

    while (paragraph_end = dpkg_status.scan_until(/Package: /))
        paragraph = "Package: #{paragraph_end[0..-10]}"
        parse_package_status(installed_packages, installed_versions,
                             paragraph, virtual: virtual)
    end
    parse_package_status(installed_packages, installed_versions,
                         "Package: #{dpkg_status.rest}", virtual: virtual)
    [installed_packages, installed_versions]
end

.parse_package_status(installed_packages, installed_versions, paragraph, virtual: true) ⇒ Object



45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
# File 'lib/autoproj/package_managers/apt_dpkg_manager.rb', line 45

def self.parse_package_status(
    installed_packages, installed_versions, paragraph, virtual: true
)
    if paragraph =~ /^Status: install ok installed$/
        if paragraph =~ /^Package: (.*)$/
            package_name = $1
            installed_packages << package_name
            if paragraph =~ /^Version: (.*)$/
                installed_versions[package_name] = DebianVersion.new($1)
            end
        end
        if virtual && paragraph =~ /^Provides: (.*)$/
            installed_packages.merge($1.split(",").map(&:strip))
        end
    end
end

.parse_packages_versions(packages) ⇒ Object



94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
# File 'lib/autoproj/package_managers/apt_dpkg_manager.rb', line 94

def self.parse_packages_versions(packages)
    packages_versions = {}
    apt_cache_show = `apt-cache show --no-all-versions #{packages.join(" ")}`
    apt_cache_show = StringScanner.new(apt_cache_show)
    return packages_versions unless apt_cache_show.scan(/Package: /)

    while (paragraph_end = apt_cache_show.scan_until(/Package: /))
        paragraph = "Package: #{paragraph_end[0..-10]}"
        package_name, version = parse_apt_cache_paragraph(paragraph)
        packages_versions[package_name] = DebianVersion.new(version)
    end
    package_name, version = parse_apt_cache_paragraph(
        "Package: #{apt_cache_show.rest}"
    )
    packages_versions[package_name] = DebianVersion.new(version)
    packages_versions
end

Instance Method Details

#configure_managerObject



27
28
29
30
31
32
33
34
35
# File 'lib/autoproj/package_managers/apt_dpkg_manager.rb', line 27

def configure_manager
    super
    ws.config.declare(
        "apt_dpkg_update", "boolean",
        default: "yes",
        doc: ["Would you like autoproj to keep apt packages up-to-date?"]
    )
    keep_uptodate?
end

#install(packages, filter_uptodate_packages: false, install_only: false) ⇒ Object

rubocop:disable Metrics/AbcSize



139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
# File 'lib/autoproj/package_managers/apt_dpkg_manager.rb', line 139

def install(packages, filter_uptodate_packages: false, install_only: false)
    if filter_uptodate_packages || install_only
        already_installed, missing = packages.partition do |package_name|
            installed?(package_name)
        end

        if keep_uptodate? && !install_only
            packages_versions = self.class.parse_packages_versions(already_installed)
            need_update = already_installed.find_all do |package_name|
                !updated?(package_name, packages_versions[package_name])
            end
        end
        packages = missing + (need_update || [])
    end

    if super(packages, inherit: self.class.inherit)
        # Invalidate caching of installed packages, as we just
        # installed new packages !
        @installed_packages = nil
    end
end

#installed?(package_name, filter_uptodate_packages: false, install_only: false) ⇒ Boolean

On a dpkg-enabled system, checks if the provided package is installed and returns true if it is the case

Returns:

  • (Boolean)


123
124
125
126
127
128
129
130
131
132
133
134
135
136
# File 'lib/autoproj/package_managers/apt_dpkg_manager.rb', line 123

def installed?(package_name, filter_uptodate_packages: false,
    install_only: false)
    unless @installed_packages && @installed_versions
        @installed_packages, @installed_versions =
            self.class.parse_dpkg_status(status_file)
    end

    if package_name =~ /^(\w[a-z0-9+-.]+)/
        @installed_packages.include?($1)
    else
        Autoproj.warn "#{package_name} is not a valid Debian package name"
        false
    end
end

#keep_uptodate=(flag) ⇒ Object



41
42
43
# File 'lib/autoproj/package_managers/apt_dpkg_manager.rb', line 41

def keep_uptodate=(flag)
    ws.config.set("apt_dpkg_update", flag, true)
end

#keep_uptodate?Boolean

Returns:

  • (Boolean)


37
38
39
# File 'lib/autoproj/package_managers/apt_dpkg_manager.rb', line 37

def keep_uptodate?
    ws.config.get("apt_dpkg_update")
end

#updated?(package, available_version) ⇒ Boolean

Returns:

  • (Boolean)


112
113
114
115
116
117
118
119
# File 'lib/autoproj/package_managers/apt_dpkg_manager.rb', line 112

def updated?(package, available_version)
    # Consider up-to-date if the package is provided by another
    # package (purely virtual) Ideally, we should check the version
    # of the package that provides it
    return true unless available_version && @installed_versions[package]

    (available_version <= @installed_versions[package])
end