Class: Autoproj::RepositoryManagers::APT
- Defined in:
- lib/autoproj/repository_managers/apt.rb
Overview
Apt repository manager class
Constant Summary collapse
- SOURCES_DIR =
"/etc/apt".freeze
- SOURCE_TYPES =
%w[deb deb-src].freeze
- AUTOPROJ_SOURCES =
"/etc/apt/sources.list.d/autoproj.list".freeze
- INVALID_REPO_MESSAGE =
"Invalid apt repository definition".freeze
Instance Attribute Summary collapse
-
#autoproj_sources ⇒ Object
readonly
Returns the value of attribute autoproj_sources.
-
#source_entries ⇒ Object
readonly
Returns the value of attribute source_entries.
-
#source_files ⇒ Object
readonly
Returns the value of attribute source_files.
-
#sources_dir ⇒ Object
readonly
Returns the value of attribute sources_dir.
Attributes inherited from Manager
Instance Method Summary collapse
- #add_apt_key(id, origin, type: :keyserver) ⇒ Object
- #add_entry_to_file(file, entry) ⇒ Object
- #add_source(source, file = nil) ⇒ Object
- #append_entry(contents, entry) ⇒ Object
- #apt_update ⇒ Object
- #enable_entry_in_file(file, enable_entry) ⇒ Object
- #entry_exist?(new_entry) ⇒ Boolean
- #filter_installed_definitions(definitions) ⇒ Object
-
#initialize(ws, sources_dir: SOURCES_DIR, autoproj_sources: AUTOPROJ_SOURCES) ⇒ APT
constructor
A new instance of APT.
-
#install(definitions) ⇒ Object
rubocop:enable Style/GuardClause.
- #key_exist?(key) ⇒ Boolean
- #load_sources_from_file(file) ⇒ Object
- #os_dependencies ⇒ Object
- #parse_source_line(line, raise_if_invalid: true) ⇒ Object
- #print_installing_definitions(definitions) ⇒ Object
- #run_tee_command(command, contents) ⇒ Object
- #source_exist?(source) ⇒ Boolean
-
#validate_definitions(definitions) ⇒ Object
Validates repositories definitions from .osrepos files.
- #validate_key_definition(definition) ⇒ Object
-
#validate_repo_definition(definition) ⇒ Object
rubocop:disable Style/GuardClause.
Constructor Details
#initialize(ws, sources_dir: SOURCES_DIR, autoproj_sources: AUTOPROJ_SOURCES) ⇒ APT
Returns a new instance of APT.
20 21 22 23 24 25 26 27 28 |
# 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 |
Instance Attribute Details
#autoproj_sources ⇒ Object (readonly)
Returns the value of attribute autoproj_sources.
14 15 16 |
# File 'lib/autoproj/repository_managers/apt.rb', line 14 def autoproj_sources @autoproj_sources end |
#source_entries ⇒ Object (readonly)
Returns the value of attribute source_entries.
12 13 14 |
# File 'lib/autoproj/repository_managers/apt.rb', line 12 def source_entries @source_entries end |
#source_files ⇒ Object (readonly)
Returns the value of attribute source_files.
11 12 13 |
# File 'lib/autoproj/repository_managers/apt.rb', line 11 def source_files @source_files end |
#sources_dir ⇒ Object (readonly)
Returns the value of attribute sources_dir.
13 14 15 |
# File 'lib/autoproj/repository_managers/apt.rb', line 13 def sources_dir @sources_dir end |
Instance Method Details
#add_apt_key(id, origin, type: :keyserver) ⇒ Object
162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 |
# 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. end |
#add_entry_to_file(file, entry) ⇒ Object
117 118 119 120 121 122 |
# 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) ⇒ Object
75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 |
# 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) ⇒ Object
96 97 98 99 100 101 102 103 104 105 |
# 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 ⇒ Object
152 153 154 155 156 157 158 159 160 |
# 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) ⇒ Object
107 108 109 110 111 112 113 114 115 |
# 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) ⇒ Boolean
129 130 131 132 133 134 135 |
# 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) ⇒ Object
192 193 194 195 196 197 198 199 200 201 202 |
# 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) ⇒ Object
rubocop:enable Style/GuardClause
307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 |
# 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) ⇒ Boolean
141 142 143 144 145 146 147 148 149 150 |
# 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) ⇒ Object
34 35 36 37 38 39 40 41 42 |
# 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 ⇒ Object
30 31 32 |
# 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) ⇒ Object
44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 |
# 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) ⇒ Object
204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 |
# File 'lib/autoproj/repository_managers/apt.rb', line 204 def print_installing_definitions(definitions) repos = definitions.select { |definition| definition["type"] == "repo" } keys = definitions.select { |definition| definition["type"] == "key" } unless repos.empty? Autoproj. " adding apt repositories:" repos.each do |repo| if repo["file"] Autoproj. " #{repo['repo']}, file: #{repo['file']}" else Autoproj. " #{repo['repo']}" end end end return if keys.empty? Autoproj. " adding apt keys:" keys.each do |key| if key["keyserver"] Autoproj. " id: #{key['id']}, keyserver: #{key['keyserver']}" else Autoproj. " id: #{key['id']}, url: #{key['url']}" end end end |
#run_tee_command(command, contents) ⇒ Object
124 125 126 127 |
# 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) ⇒ Boolean
137 138 139 |
# File 'lib/autoproj/repository_managers/apt.rb', line 137 def source_exist?(source) entry_exist?(parse_source_line(source)) end |
#validate_definitions(definitions) ⇒ Object
Validates repositories definitions from .osrepos files
Examples:
-
ubuntu:
-
xenial: type: repo repo: ‘deb archive.ubuntu.com/ubuntu/ xenial main restricted’
-
-
ubuntu:
-
xenial: type: key id: 630239CC130E1A7FD81A27B140976EAF437D05B5 keyserver: ‘hkp://ha.pool.sks-keyservers.net:80’
-
-
ubuntu:
-
xenial: type: key id: D2486D2DD83DB69272AFE98867170598AF249743 url: ‘packages.osrfoundation.org/gazebo.key’
-
251 252 253 254 255 256 257 258 259 260 261 262 263 |
# 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) ⇒ Object
287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 |
# 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) ⇒ Object
rubocop:disable Style/GuardClause
269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 |
# 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 |