Class: Autoproj::OSPackageResolver
- Inherits:
-
Object
- Object
- Autoproj::OSPackageResolver
- Defined in:
- lib/autoproj/os_package_resolver.rb
Overview
Manager for packages provided by external package managers
Defined Under Namespace
Classes: InvalidRecursiveStatement, OSDepRecursiveResolver
Constant Summary collapse
- AUTOPROJ_OSDEPS =
File.join(__dir__, "default.osdeps")
- PACKAGE_MANAGERS =
OSPackageInstaller::PACKAGE_MANAGERS.keys
- 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.
{ "debian" => "apt-dpkg", "gentoo" => "emerge", "arch" => "pacman", "fedora" => "yum", "macos-port" => "macports", "macos-brew" => "brew", "opensuse" => "zypper", "freebsd" => "pkg" }.freeze
- FOUND_PACKAGES =
Value returned by #resolve_package and #partition_osdep_entry in the status field. See the documentation of these methods for more information
0
- FOUND_NONEXISTENT =
Value returned by #resolve_package and #partition_osdep_entry in the status field. See the documentation of these methods for more information
1
- NO_PACKAGE =
Value returned by #availability_of if the required package has no definition
0
- WRONG_OS =
Value returned by #availability_of if the required package has definitions, but not for this OS name or version
1
- UNKNOWN_OS =
Value returned by #availability_of if the required package has definitions, but the local OS is unknown
2
- NONEXISTENT =
Value returned by #availability_of if the required package has definitions, but the nonexistent keyword was used for this OS
3
- AVAILABLE =
Value returned by #availability_of if the required package is available
4
- IGNORE =
Value returned by #availability_of if the required package is available, but no package needs to be installed to have it
5
Instance Attribute Summary collapse
-
#aliases ⇒ Object
readonly
Aliases for osdep packages.
-
#all_definitions ⇒ Object
readonly
All the information contained in all the OSdeps files, as a mapping from the OSdeps package name to [osdeps_file, definition] pairs.
-
#definitions ⇒ Object
readonly
The information contained in the OSdeps files, as a hash.
-
#package_managers ⇒ Array<String>
readonly
Returns the set of known package managers.
-
#prefer_indep_over_os_packages ⇒ Object
writeonly
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).
-
#resolve_package_cache ⇒ Object
readonly
Cached results of #resolve_package.
-
#sources ⇒ Object
readonly
The information as to from which osdeps file the current package information in
definitions
originates. -
#ws ⇒ Object
readonly
The underlying workspace.
Class Method Summary collapse
-
.autodetect_operating_system ⇒ Object
Autodetects the operating system name and version.
- .autodetect_ruby_program ⇒ Object
- .ensure_derivatives_refer_to_their_parents(names) ⇒ Object
- .guess_operating_system ⇒ Object
- .load(file, suffixes: [], **options) ⇒ Object
- .load_default ⇒ Object
- .normalize_os_representation(names, versions) ⇒ Object
- .os_from_lsb ⇒ Object
- .os_from_os_release(filename = "/etc/os-release") ⇒ Object
-
.verify_definitions(hash, path = []) ⇒ Object
Perform some sanity checks on the given osdeps definitions.
Instance Method Summary collapse
-
#add_aliases(new_aliases) ⇒ Object
Register new aliases.
- #add_entries(entries, file: nil) ⇒ Object
-
#all_package_names ⇒ Object
Returns the name of all known OS packages.
-
#availability_of(name) ⇒ Object
If
name
is an osdeps that is available for this operating system, returns AVAILABLE. -
#has?(name) ⇒ Boolean
Returns true if
name
is an acceptable OS package for this OS and version. -
#include?(name) ⇒ Boolean
Returns true if the given name has an entry in the osdeps.
-
#initialize(defs = Hash.new, file = nil, operating_system: nil, package_managers: PACKAGE_MANAGERS.dup, os_package_manager: nil) ⇒ OSPackageResolver
constructor
The Gem::SpecFetcher object that should be used to query RubyGems, and install RubyGems packages.
- #invalidate_resolve_package_cache ⇒ Object
-
#known_operating_system? ⇒ Boolean
Whether the operating system could be autodetected successfully.
- #load_default ⇒ Object
-
#merge(info, suffixes: []) ⇒ Object
Merges the osdeps information of
info
intoself
. -
#operating_system ⇒ Object
The operating system self is targetting.
-
#operating_system=(values) ⇒ Object
Change the operating system this resolver is targetting.
-
#os_package_manager ⇒ String
Returns the name of the package manager object for the current OS.
-
#os_package_manager=(manager_name) ⇒ Object
Use to override the autodetected OS-specific package handler.
-
#partition_osdep_entry(osdep_name, dep_def, handler_names, excluded, *keys) ⇒ Object
Helper method that parses the osdep definition to split between the parts needed for this OS and specific package handlers.
- #partition_osdep_map_entry(names, values, osdep_name, handler_names, excluded, keys, found_keys, additional_keys) ⇒ Object
- #partition_osdep_raw_array_entry(names, osdep_name, handler_names, excluded, keys, additional_keys) ⇒ Object
-
#prefer_indep_over_os_packages? ⇒ Boolean
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).
-
#resolve_name(name) ⇒ Object
Return the path to the osdeps name for a given package name while accounting for package aliases.
-
#resolve_os_packages(dependencies) ⇒ Array<#install,Array<String>>
Resolves the given OS dependencies into the actual packages that need to be installed on this particular OS.
-
#resolve_package(name, resolve_recursive: true) ⇒ Object
Return the list of packages that should be installed for
name
. -
#source_of(package_name) ⇒ Object
Returns the full path to the osdeps file from which the package definition for
package_name
has been taken. -
#supported_operating_system? ⇒ Boolean
Returns true if it is possible to install packages for the operating system on which we are installed.
-
#warn_about_merge_collisions(merged_info, suffixes, key, _old_value, _new_value) ⇒ Object
private
Warn about a collision (override) detected during #merge.
Constructor Details
#initialize(defs = Hash.new, file = nil, operating_system: nil, package_managers: PACKAGE_MANAGERS.dup, os_package_manager: nil) ⇒ OSPackageResolver
The Gem::SpecFetcher object that should be used to query RubyGems, and install RubyGems packages
143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 |
# 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 = @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 |
Instance Attribute Details
#aliases ⇒ Object (readonly)
Aliases for osdep packages
139 140 141 |
# File 'lib/autoproj/os_package_resolver.rb', line 139 def aliases @aliases end |
#all_definitions ⇒ Object (readonly)
All the information contained in all the OSdeps files, as a mapping from the OSdeps package name to [osdeps_file, definition] pairs
94 95 96 |
# File 'lib/autoproj/os_package_resolver.rb', line 94 def all_definitions @all_definitions end |
#definitions ⇒ Object (readonly)
The information contained in the OSdeps files, as a hash
91 92 93 |
# File 'lib/autoproj/os_package_resolver.rb', line 91 def definitions @definitions end |
#package_managers ⇒ Array<String> (readonly)
Returns the set of known package managers
136 137 138 |
# File 'lib/autoproj/os_package_resolver.rb', line 136 def package_managers @package_managers end |
#prefer_indep_over_os_packages=(value) ⇒ Object (writeonly)
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)
107 108 109 |
# File 'lib/autoproj/os_package_resolver.rb', line 107 def prefer_indep_over_os_packages=(value) @prefer_indep_over_os_packages = value end |
#resolve_package_cache ⇒ Object (readonly)
Cached results of #resolve_package
109 110 111 |
# File 'lib/autoproj/os_package_resolver.rb', line 109 def resolve_package_cache @resolve_package_cache end |
#sources ⇒ Object (readonly)
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
98 99 100 |
# File 'lib/autoproj/os_package_resolver.rb', line 98 def sources @sources end |
#ws ⇒ Object (readonly)
The underlying workspace
41 42 43 |
# File 'lib/autoproj/os_package_resolver.rb', line 41 def ws @ws end |
Class Method Details
.autodetect_operating_system ⇒ Object
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’]]
421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 |
# File 'lib/autoproj/os_package_resolver.rb', line 421 def self. 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 = 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 ⇒ Object
43 44 45 46 47 48 49 |
# 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) ⇒ Object
374 375 376 377 378 379 380 381 382 383 384 385 386 |
# 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 ⇒ Object
323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 |
# File 'lib/autoproj/os_package_resolver.rb', line 323 def self. 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) ⇒ Object
7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 |
# File 'lib/autoproj/os_package_resolver.rb', line 7 def self.load(file, suffixes: [], **) 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(**) candidates.each do |file_candidate| next unless File.file?(file_candidate) file_candidate = File.(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.}", e.backtrace end result.merge(new(data, file_candidate, **)) end result end |
.load_default ⇒ Object
52 53 54 55 56 57 58 59 60 |
# 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 |
.normalize_os_representation(names, versions) ⇒ Object
388 389 390 391 392 393 394 |
# 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 ⇒ Object
479 480 481 482 483 484 485 486 487 |
# 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") ⇒ Object
456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 |
# 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 = []) ⇒ Object
Perform some sanity checks on the given osdeps definitions
272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 |
# 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 |
Instance Method Details
#add_aliases(new_aliases) ⇒ Object
Register new aliases
177 178 179 |
# File 'lib/autoproj/os_package_resolver.rb', line 177 def add_aliases(new_aliases) aliases.merge!(new_aliases) end |
#add_entries(entries, file: nil) ⇒ Object
195 196 197 |
# 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 ⇒ Object
Returns the name of all known OS packages
It includes even the packages for which there are no definitions on this OS
185 186 187 |
# File 'lib/autoproj/os_package_resolver.rb', line 185 def all_package_names definitions.keys end |
#availability_of(name) ⇒ Object
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
896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 |
# 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 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) ⇒ Boolean
Returns true if name
is an acceptable OS package for this OS and version
861 862 863 864 |
# File 'lib/autoproj/os_package_resolver.rb', line 861 def has?(name) status = availability_of(name) [AVAILABLE, IGNORE].include?(status) end |
#include?(name) ⇒ Boolean
Returns true if the given name has an entry in the osdeps
855 856 857 |
# File 'lib/autoproj/os_package_resolver.rb', line 855 def include?(name) definitions.key?(name) end |
#invalidate_resolve_package_cache ⇒ Object
199 200 201 |
# File 'lib/autoproj/os_package_resolver.rb', line 199 def invalidate_resolve_package_cache @resolve_package_cache.clear end |
#known_operating_system? ⇒ Boolean
Whether the operating system could be autodetected successfully
309 310 311 312 |
# File 'lib/autoproj/os_package_resolver.rb', line 309 def os_names, = !os_names.empty? end |
#load_default ⇒ Object
62 63 64 |
# File 'lib/autoproj/os_package_resolver.rb', line 62 def load_default merge(self.class.load_default) end |
#merge(info, suffixes: []) ⇒ Object
Merges the osdeps information of info
into self
. If packages are defined in both OSPackageResolver objects, the information in info
takes precedence
206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 |
# 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 ⇒ Object
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
400 401 402 |
# File 'lib/autoproj/os_package_resolver.rb', line 400 def @operating_system ||= self.class. end |
#operating_system=(values) ⇒ Object
Change the operating system this resolver is targetting
405 406 407 408 409 |
# File 'lib/autoproj/os_package_resolver.rb', line 405 def (values) @supported_operating_system = nil @os_package_manager = nil @operating_system = values end |
#os_package_manager ⇒ String
Returns the name of the package manager object for the current OS
124 125 126 127 128 129 130 131 |
# File 'lib/autoproj/os_package_resolver.rb', line 124 def os_package_manager unless @os_package_manager os_names, = 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) ⇒ Object
Use to override the autodetected OS-specific package handler
112 113 114 115 116 117 118 119 |
# 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) ⇒ Object
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.
658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 |
# 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) ⇒ Object
753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 |
# 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) ⇒ Object
706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 |
# 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? ⇒ Boolean
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)
103 104 105 |
# File 'lib/autoproj/os_package_resolver.rb', line 103 def prefer_indep_over_os_packages? @prefer_indep_over_os_packages end |
#resolve_name(name) ⇒ Object
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
496 497 498 499 500 501 502 503 |
# 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) ⇒ Array<#install,Array<String>>
Resolves the given OS dependencies into the actual packages that need to be installed on this particular OS.
808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 |
# 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 = 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) ⇒ Object
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.
530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 |
# 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 = # 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) ⇒ Object
Returns the full path to the osdeps file from which the package definition for package_name
has been taken
191 192 193 |
# File 'lib/autoproj/os_package_resolver.rb', line 191 def source_of(package_name) sources[package_name] end |
#supported_operating_system? ⇒ Boolean
Returns true if it is possible to install packages for the operating system on which we are installed
316 317 318 319 320 321 |
# File 'lib/autoproj/os_package_resolver.rb', line 316 def 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) ⇒ Object
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Warn about a collision (override) detected during #merge
231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 |
# 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 |