autoproj 2.9.0 → 2.10.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.rubocop.yml +113 -0
- data/.travis.yml +0 -2
- data/Gemfile +1 -0
- data/README.md +59 -14
- data/bin/autoproj_bootstrap +21 -12
- data/bin/autoproj_bootstrap.in +2 -2
- data/bin/autoproj_install +21 -12
- data/bin/autoproj_install.in +2 -2
- data/lib/autoproj/aruba_minitest.rb +4 -4
- data/lib/autoproj/autobuild_extensions/dsl.rb +91 -70
- data/lib/autoproj/autobuild_extensions/package.rb +20 -1
- data/lib/autoproj/build_option.rb +24 -7
- data/lib/autoproj/cli/base.rb +12 -1
- data/lib/autoproj/cli/bootstrap.rb +9 -3
- data/lib/autoproj/cli/build.rb +17 -13
- data/lib/autoproj/cli/envsh.rb +1 -1
- data/lib/autoproj/cli/exec.rb +5 -7
- data/lib/autoproj/cli/main.rb +44 -9
- data/lib/autoproj/cli/main_test.rb +2 -0
- data/lib/autoproj/cli/test.rb +29 -6
- data/lib/autoproj/cli/version.rb +52 -0
- data/lib/autoproj/cli/versions.rb +4 -1
- data/lib/autoproj/cli/watch.rb +2 -1
- data/lib/autoproj/configuration.rb +49 -11
- data/lib/autoproj/default.osdeps +9 -0
- data/lib/autoproj/manifest.rb +6 -6
- data/lib/autoproj/ops/build.rb +5 -15
- data/lib/autoproj/ops/import.rb +22 -3
- data/lib/autoproj/ops/install.rb +19 -10
- data/lib/autoproj/ops/main_config_switcher.rb +12 -6
- data/lib/autoproj/ops/snapshot.rb +5 -1
- data/lib/autoproj/os_package_resolver.rb +245 -209
- data/lib/autoproj/package_selection.rb +18 -0
- data/lib/autoproj/reporter.rb +45 -31
- data/lib/autoproj/test.rb +107 -56
- data/lib/autoproj/version.rb +1 -1
- data/lib/autoproj/workspace.rb +90 -72
- data/shell/completion/amake_bash +1 -0
- data/shell/completion/amake_zsh +1 -0
- data/shell/completion/autoproj_bash +2 -0
- data/shell/completion/autoproj_zsh +2 -0
- metadata +5 -3
data/lib/autoproj/default.osdeps
CHANGED
@@ -162,6 +162,15 @@ pip:
|
|
162
162
|
freebsd: pip
|
163
163
|
default: ignore # assume pip will be installed by the user
|
164
164
|
|
165
|
+
python:
|
166
|
+
arch: python2
|
167
|
+
debian,ubuntu: python-dev
|
168
|
+
fedora: python-devel
|
169
|
+
freebsd: python-devel
|
170
|
+
gentoo: dev-lang/python
|
171
|
+
opensuse: python-devel
|
172
|
+
default: ignore # will be installed manually by the user
|
173
|
+
|
165
174
|
sudo:
|
166
175
|
macos-brew: ignore
|
167
176
|
default: sudo
|
data/lib/autoproj/manifest.rb
CHANGED
@@ -19,11 +19,11 @@ class Manifest
|
|
19
19
|
|
20
20
|
# Loads the manifest file located at +file+ and returns the Manifest
|
21
21
|
# instance that represents it
|
22
|
-
|
23
|
-
|
22
|
+
def self.load(file)
|
23
|
+
manifest = Manifest.new
|
24
24
|
manifest.load(file)
|
25
25
|
manifest
|
26
|
-
|
26
|
+
end
|
27
27
|
|
28
28
|
# A normalized version of the layout as represented in the manifest file
|
29
29
|
#
|
@@ -176,7 +176,7 @@ def initialize(ws, os_package_resolver: OSPackageResolver.new)
|
|
176
176
|
@ws = ws
|
177
177
|
@vcs = VCSDefinition.none
|
178
178
|
@file = nil
|
179
|
-
|
179
|
+
@data = Hash.new
|
180
180
|
@has_layout = false
|
181
181
|
@normalized_layout = Hash.new
|
182
182
|
@packages = Hash.new
|
@@ -198,7 +198,7 @@ def initialize(ws, os_package_resolver: OSPackageResolver.new)
|
|
198
198
|
|
199
199
|
@constant_definitions = Hash.new
|
200
200
|
@package_sets << LocalPackageSet.new(ws)
|
201
|
-
|
201
|
+
end
|
202
202
|
|
203
203
|
# @api private
|
204
204
|
#
|
@@ -994,7 +994,7 @@ def load_package_manifest(pkg)
|
|
994
994
|
|
995
995
|
# Look for the package's manifest.xml, but fallback to a manifest in
|
996
996
|
# the package set if present
|
997
|
-
if package.use_package_xml?
|
997
|
+
if package.use_package_xml? && package.checked_out?
|
998
998
|
manifest_path = File.join(package.srcdir, "package.xml")
|
999
999
|
raise NoPackageXML.new(package.srcdir), "#{package.name} from "\
|
1000
1000
|
"#{package_set.name} has use_package_xml set, but the package has "\
|
data/lib/autoproj/ops/build.rb
CHANGED
@@ -13,9 +13,9 @@ class Build
|
|
13
13
|
|
14
14
|
# @param [String] report_dir the log directory in which to build
|
15
15
|
# the build report. If left to nil, no report will be generated
|
16
|
-
def initialize(manifest,
|
16
|
+
def initialize(manifest, report_path: nil)
|
17
17
|
@manifest = manifest
|
18
|
-
@
|
18
|
+
@report_path = report_path
|
19
19
|
end
|
20
20
|
|
21
21
|
# Triggers a rebuild of all packages
|
@@ -92,22 +92,12 @@ def build_packages(all_enabled_packages, options = Hash.new)
|
|
92
92
|
begin
|
93
93
|
Autobuild.apply(all_enabled_packages, "autoproj-build", ['build'], options)
|
94
94
|
ensure
|
95
|
-
build_report(all_enabled_packages) if @
|
95
|
+
build_report(all_enabled_packages) if @report_path
|
96
96
|
end
|
97
97
|
end
|
98
98
|
|
99
|
-
REPORT_BASENAME = "build_report.json"
|
100
|
-
|
101
|
-
# The path to the report file
|
102
|
-
#
|
103
|
-
# @return [String,nil] the path, or nil if the report should not
|
104
|
-
# be generated
|
105
|
-
def report_path
|
106
|
-
File.join(@report_dir, REPORT_BASENAME) if @report_dir
|
107
|
-
end
|
108
|
-
|
109
99
|
def build_report(package_list)
|
110
|
-
FileUtils.mkdir_p @
|
100
|
+
FileUtils.mkdir_p File.dirname(@report_path)
|
111
101
|
|
112
102
|
packages = package_list.map do |pkg_name|
|
113
103
|
pkg = manifest.find_autobuild_package(pkg_name)
|
@@ -130,7 +120,7 @@ def build_report(package_list)
|
|
130
120
|
packages: packages
|
131
121
|
}
|
132
122
|
})
|
133
|
-
IO.write(report_path, build_report)
|
123
|
+
IO.write(@report_path, build_report)
|
134
124
|
end
|
135
125
|
end
|
136
126
|
end
|
data/lib/autoproj/ops/import.rb
CHANGED
@@ -73,7 +73,7 @@ def import_next_step(pkg, reverse_dependencies)
|
|
73
73
|
end
|
74
74
|
new_packages
|
75
75
|
end
|
76
|
-
|
76
|
+
|
77
77
|
def pre_package_import(selection, manifest, pkg, reverse_dependencies)
|
78
78
|
# Try to auto-exclude the package early. If the autobuild file
|
79
79
|
# contained some information that allows us to exclude it now,
|
@@ -133,12 +133,30 @@ def install_vcs_packages_for(*packages, **osdeps_options)
|
|
133
133
|
vcs_to_install
|
134
134
|
end
|
135
135
|
|
136
|
+
# Install the internal dependencies for the given packages
|
137
|
+
#
|
138
|
+
# @param [Hash] osdeps_options the options that will be passed to
|
139
|
+
# {Workspace#install_os_packages}
|
140
|
+
# @return [Set] the set of installed OS packages
|
141
|
+
def install_internal_dependencies_for(*packages, **osdeps_options)
|
142
|
+
packages_to_install = packages.map do |pkg|
|
143
|
+
pkg.autobuild.internal_dependencies
|
144
|
+
end.flatten.uniq
|
145
|
+
return if packages_to_install.empty?
|
146
|
+
|
147
|
+
# This assumes that the internal dependencies do not depend on a
|
148
|
+
# 'strict' package mangers such as e.g. BundlerManager and that
|
149
|
+
# the package manager itself does not have any dependencies
|
150
|
+
ws.install_os_packages(packages_to_install, all: nil, **osdeps_options)
|
151
|
+
packages_to_install
|
152
|
+
end
|
153
|
+
|
136
154
|
# @api private
|
137
155
|
#
|
138
156
|
# Queue the work necessary to import the given package, making sure
|
139
157
|
# that the execution results end up in a given queue
|
140
158
|
#
|
141
|
-
# @param executor the future executor
|
159
|
+
# @param executor the future executor
|
142
160
|
# @param [Queue] completion_queue the queue where the completion
|
143
161
|
# results should be pushed, as a (package, time, result,
|
144
162
|
# error_reason) tuple
|
@@ -331,7 +349,7 @@ def import_selected_packages(selection,
|
|
331
349
|
executor.wait_for_termination
|
332
350
|
end
|
333
351
|
end
|
334
|
-
|
352
|
+
|
335
353
|
def finalize_package_load(processed_packages, auto_exclude: auto_exclude?)
|
336
354
|
manifest = ws.manifest
|
337
355
|
|
@@ -405,6 +423,7 @@ def import_packages(selection,
|
|
405
423
|
raise failures.first
|
406
424
|
end
|
407
425
|
|
426
|
+
install_internal_dependencies_for(*all_processed_packages)
|
408
427
|
finalize_package_load(all_processed_packages, auto_exclude: auto_exclude)
|
409
428
|
|
410
429
|
all_enabled_osdeps = selection.each_osdep_package_name.to_set
|
data/lib/autoproj/ops/install.rb
CHANGED
@@ -229,6 +229,9 @@ def parse_options(args = ARGV)
|
|
229
229
|
opt.on '--skip-stage2', 'do not run the stage2 install' do
|
230
230
|
@skip_stage2 = true
|
231
231
|
end
|
232
|
+
opt.on '--debug', 'Run in debug mode' do
|
233
|
+
@autoproj_options << '--debug'
|
234
|
+
end
|
232
235
|
opt.on '--gem-source=URL', String, "use this source for RubyGems "\
|
233
236
|
"instead of rubygems.org" do |url|
|
234
237
|
@gem_source = url
|
@@ -265,19 +268,25 @@ def parse_options(args = ARGV)
|
|
265
268
|
end
|
266
269
|
opt.on '--[no-]color', 'do not use colored output (enabled by "\
|
267
270
|
"default if the terminal supports it)' do |color|
|
268
|
-
if color then autoproj_options << "--color"
|
269
|
-
else autoproj_options << '--no-color'
|
271
|
+
if color then @autoproj_options << "--color"
|
272
|
+
else @autoproj_options << '--no-color'
|
270
273
|
end
|
271
274
|
end
|
272
275
|
opt.on '--[no-]progress', 'do not use progress output (enabled by "\
|
273
|
-
"default if the terminal supports it)' do |
|
274
|
-
if
|
275
|
-
else autoproj_options << '--no-progress'
|
276
|
+
"default if the terminal supports it)' do |progress|
|
277
|
+
if progress then @autoproj_options << "--progress"
|
278
|
+
else @autoproj_options << '--no-progress'
|
279
|
+
end
|
280
|
+
end
|
281
|
+
opt.on '--[no-]interactive', 'if non-interactive, use default "\
|
282
|
+
"answer for questions' do |flag|
|
283
|
+
if flag then @autoproj_options << "--interactive"
|
284
|
+
else @autoproj_options << "--no-interactive"
|
276
285
|
end
|
277
286
|
end
|
278
287
|
end
|
279
288
|
args = options.parse(ARGV)
|
280
|
-
autoproj_options + args
|
289
|
+
@autoproj_options + args
|
281
290
|
end
|
282
291
|
|
283
292
|
def find_bundler(gem_program)
|
@@ -667,7 +676,7 @@ def autoproj_path
|
|
667
676
|
|
668
677
|
def run_autoproj(*args)
|
669
678
|
system env_for_child.merge('BUNDLE_GEMFILE' => autoproj_gemfile_path),
|
670
|
-
Gem.ruby, autoproj_path, *args,
|
679
|
+
Gem.ruby, autoproj_path, *args, *@autoproj_options
|
671
680
|
end
|
672
681
|
|
673
682
|
def v1_workspace?
|
@@ -691,7 +700,7 @@ def call_stage2
|
|
691
700
|
clean_env = env_for_child
|
692
701
|
stage2_vars = clean_env.map { |k, v| "#{k}=#{v}" }
|
693
702
|
puts "starting the newly installed autoproj for stage2 install"
|
694
|
-
if !run_autoproj('install-stage2', root_dir, *stage2_vars)
|
703
|
+
if !run_autoproj('install-stage2', root_dir, *stage2_vars, *@autoproj_options)
|
695
704
|
raise "failed to execute autoproj install-stage2"
|
696
705
|
end
|
697
706
|
end
|
@@ -701,7 +710,7 @@ def stage2(*vars)
|
|
701
710
|
puts "saving temporary env.sh and .autoproj/env.sh"
|
702
711
|
save_env_sh(*vars)
|
703
712
|
puts "running 'autoproj envsh' to generate a proper env.sh"
|
704
|
-
if !system(Gem.ruby, autoproj_path, 'envsh',
|
713
|
+
if !system(Gem.ruby, autoproj_path, 'envsh', *@autoproj_options)
|
705
714
|
STDERR.puts "failed to run autoproj envsh on the newly installed "\
|
706
715
|
"autoproj (#{autoproj_path})"
|
707
716
|
exit 1
|
@@ -709,7 +718,7 @@ def stage2(*vars)
|
|
709
718
|
# This is really needed on an existing install to install the
|
710
719
|
# gems that were present in the v1 layout
|
711
720
|
puts "running 'autoproj osdeps' to re-install missing gems"
|
712
|
-
if !system(Gem.ruby, autoproj_path, 'osdeps')
|
721
|
+
if !system(Gem.ruby, autoproj_path, 'osdeps', *@autoproj_options)
|
713
722
|
STDERR.puts "failed to run autoproj osdeps on the newly installed "\
|
714
723
|
"autoproj (#{autoproj_path})"
|
715
724
|
exit 1
|
@@ -16,16 +16,20 @@ def initialize(ws)
|
|
16
16
|
EXPECTED_ROOT_ENTRIES = [".", "..", "autoproj_bootstrap",
|
17
17
|
".autoproj", "bootstrap.sh", ENV_FILENAME].to_set
|
18
18
|
|
19
|
+
|
20
|
+
def check_root_dir_empty?
|
21
|
+
(ENV['AUTOPROJ_NONINTERACTIVE'] != '1') &&
|
22
|
+
(ENV['AUTOPROJ_BOOTSTRAP_IGNORE_NONEMPTY_DIR'] != '1')
|
23
|
+
end
|
24
|
+
|
19
25
|
# Verifies that {#root_dir} contains only expected entries, to make
|
20
26
|
# sure that the user bootstraps into a new directory
|
21
27
|
#
|
22
28
|
# If the environment variable AUTOPROJ_BOOTSTRAP_IGNORE_NONEMPTY_DIR
|
23
29
|
# is set to 1, the check is skipped
|
24
30
|
def check_root_dir_empty
|
25
|
-
return if ENV['AUTOPROJ_BOOTSTRAP_IGNORE_NONEMPTY_DIR'] == '1'
|
26
|
-
|
27
31
|
require 'set'
|
28
|
-
curdir_entries = Dir.entries(ws.root_dir).map { |p| File.basename(p) }.to_set -
|
32
|
+
curdir_entries = Dir.entries(ws.root_dir).map { |p| File.basename(p) }.to_set -
|
29
33
|
EXPECTED_ROOT_ENTRIES
|
30
34
|
return if curdir_entries.empty?
|
31
35
|
|
@@ -73,8 +77,10 @@ def validate_autoproj_current_root(reuse)
|
|
73
77
|
|
74
78
|
MAIN_CONFIGURATION_TEMPLATE = File.expand_path(File.join("..", "..", "..", "samples", 'autoproj'), File.dirname(__FILE__))
|
75
79
|
|
76
|
-
def bootstrap(buildconf_info,
|
77
|
-
|
80
|
+
def bootstrap(buildconf_info,
|
81
|
+
check_root_dir_empty: check_root_dir_empty?,
|
82
|
+
reuse: Array.new)
|
83
|
+
self.check_root_dir_empty if check_root_dir_empty
|
78
84
|
validate_autoproj_current_root(reuse)
|
79
85
|
|
80
86
|
ws.config.validate_ruby_executable
|
@@ -179,7 +185,7 @@ def do_switch_config(delete_current, type, url, *options)
|
|
179
185
|
backup_name = "#{backup_base_name}-#{index}.bak"
|
180
186
|
index += 1
|
181
187
|
end
|
182
|
-
|
188
|
+
|
183
189
|
FileUtils.mv config_dir, backup_name
|
184
190
|
end
|
185
191
|
|
@@ -117,7 +117,7 @@ def error_or_warn(package, error)
|
|
117
117
|
end
|
118
118
|
end
|
119
119
|
|
120
|
-
def snapshot_packages(packages, target_dir = nil, only_local: true)
|
120
|
+
def snapshot_packages(packages, target_dir = nil, only_local: true, fingerprint: false)
|
121
121
|
result = Array.new
|
122
122
|
packages.each do |package_name|
|
123
123
|
package = manifest.find_package_definition(package_name)
|
@@ -140,6 +140,10 @@ def snapshot_packages(packages, target_dir = nil, only_local: true)
|
|
140
140
|
next
|
141
141
|
end
|
142
142
|
|
143
|
+
if fingerprint
|
144
|
+
vcs_info['fingerprint'] = package.autobuild.fingerprint
|
145
|
+
end
|
146
|
+
|
143
147
|
if vcs_info
|
144
148
|
result << Hash[package_name, vcs_info]
|
145
149
|
else
|
@@ -5,31 +5,35 @@ module Autoproj
|
|
5
5
|
# Manager for packages provided by external package managers
|
6
6
|
class OSPackageResolver
|
7
7
|
def self.load(file, suffixes: [], **options)
|
8
|
-
|
9
|
-
|
10
|
-
|
8
|
+
unless File.file?(file)
|
9
|
+
raise ArgumentError, "no such file or directory #{file}"
|
10
|
+
end
|
11
|
+
|
12
|
+
candidates = [file]
|
13
|
+
candidates.concat(suffixes.map { |s| "#{file}-#{s}" })
|
11
14
|
|
12
|
-
|
13
|
-
|
15
|
+
error_t =
|
16
|
+
if defined? Psych::SyntaxError
|
17
|
+
[ArgumentError, Psych::SyntaxError]
|
18
|
+
else ArgumentError
|
19
|
+
end
|
14
20
|
|
15
|
-
|
16
|
-
|
17
|
-
|
21
|
+
result = new(**options)
|
22
|
+
candidates.each do |file_candidate|
|
23
|
+
next unless File.file?(file_candidate)
|
18
24
|
|
19
|
-
result = new(**options)
|
20
|
-
candidates.each do |file_candidate|
|
21
|
-
next if !File.file?(file_candidate)
|
22
25
|
file_candidate = File.expand_path(file_candidate)
|
23
26
|
begin
|
24
|
-
data = YAML.
|
27
|
+
data = YAML.safe_load(File.read(file_candidate)) || Hash.new
|
25
28
|
verify_definitions(data)
|
26
29
|
rescue *error_t => e
|
27
|
-
raise ConfigError.new, "error in #{file_candidate}:
|
30
|
+
raise ConfigError.new, "error in #{file_candidate}: "\
|
31
|
+
"#{e.message}", e.backtrace
|
28
32
|
end
|
29
33
|
|
30
34
|
result.merge(new(data, file_candidate, **options))
|
31
|
-
|
32
|
-
|
35
|
+
end
|
36
|
+
result
|
33
37
|
end
|
34
38
|
|
35
39
|
# The underlying workspace
|
@@ -43,11 +47,12 @@ def self.autodetect_ruby_program
|
|
43
47
|
ruby_executable
|
44
48
|
end
|
45
49
|
|
46
|
-
AUTOPROJ_OSDEPS = File.join(
|
50
|
+
AUTOPROJ_OSDEPS = File.join(__dir__, 'default.osdeps')
|
47
51
|
def self.load_default
|
48
52
|
file = ENV['AUTOPROJ_DEFAULT_OSDEPS'] || AUTOPROJ_OSDEPS
|
49
|
-
|
50
|
-
Autoproj.warn "#{file} (from AUTOPROJ_DEFAULT_OSDEPS) is not a file,
|
53
|
+
unless File.file?(file)
|
54
|
+
Autoproj.warn "#{file} (from AUTOPROJ_DEFAULT_OSDEPS) is not a file, "\
|
55
|
+
"falling back to #{AUTOPROJ_OSDEPS}"
|
51
56
|
file = AUTOPROJ_OSDEPS
|
52
57
|
end
|
53
58
|
load(file)
|
@@ -58,7 +63,7 @@ def load_default
|
|
58
63
|
end
|
59
64
|
|
60
65
|
PACKAGE_MANAGERS = OSPackageInstaller::PACKAGE_MANAGERS.keys
|
61
|
-
|
66
|
+
|
62
67
|
# Mapping from OS name to package manager name
|
63
68
|
#
|
64
69
|
# Package handlers and OSes MUST have different names. The former are
|
@@ -71,15 +76,15 @@ def load_default
|
|
71
76
|
#
|
72
77
|
# we need to be able to separate between OS and package manager names.
|
73
78
|
OS_PACKAGE_MANAGERS = {
|
74
|
-
'debian'
|
75
|
-
'gentoo'
|
76
|
-
'arch'
|
77
|
-
'fedora'
|
79
|
+
'debian' => 'apt-dpkg',
|
80
|
+
'gentoo' => 'emerge',
|
81
|
+
'arch' => 'pacman',
|
82
|
+
'fedora' => 'yum',
|
78
83
|
'macos-port' => 'macports',
|
79
84
|
'macos-brew' => 'brew',
|
80
|
-
'opensuse'
|
81
|
-
'freebsd'
|
82
|
-
}
|
85
|
+
'opensuse' => 'zypper',
|
86
|
+
'freebsd' => 'pkg'
|
87
|
+
}.freeze
|
83
88
|
|
84
89
|
# The information contained in the OSdeps files, as a hash
|
85
90
|
attr_reader :definitions
|
@@ -93,16 +98,20 @@ def load_default
|
|
93
98
|
# Controls whether the package resolver will prefer installing
|
94
99
|
# OS-independent packages (such as e.g. Gems) over their OS-provided
|
95
100
|
# equivalent (e.g. the packaged version of a gem)
|
96
|
-
def prefer_indep_over_os_packages
|
101
|
+
def prefer_indep_over_os_packages?
|
102
|
+
@prefer_indep_over_os_packages
|
103
|
+
end
|
97
104
|
# (see prefer_indep_over_os_packages?)
|
98
|
-
|
105
|
+
attr_writer :prefer_indep_over_os_packages
|
99
106
|
# Cached results of {#resolve_package}
|
100
107
|
attr_reader :resolve_package_cache
|
101
108
|
|
102
109
|
# Use to override the autodetected OS-specific package handler
|
103
110
|
def os_package_manager=(manager_name)
|
104
111
|
if manager_name && !package_managers.include?(manager_name)
|
105
|
-
raise ArgumentError, "#{manager_name} is not a known
|
112
|
+
raise ArgumentError, "#{manager_name} is not a known "\
|
113
|
+
"package manager, known managers are "\
|
114
|
+
"#{package_managers.to_a.sort.join(', ')}"
|
106
115
|
end
|
107
116
|
@os_package_manager = manager_name
|
108
117
|
end
|
@@ -111,13 +120,12 @@ def os_package_manager=(manager_name)
|
|
111
120
|
#
|
112
121
|
# @return [String]
|
113
122
|
def os_package_manager
|
114
|
-
|
115
|
-
os_names,
|
123
|
+
unless @os_package_manager
|
124
|
+
os_names, = operating_system
|
116
125
|
os_name = os_names.find { |name| OS_PACKAGE_MANAGERS[name] }
|
117
|
-
@os_package_manager = OS_PACKAGE_MANAGERS[os_name] ||
|
118
|
-
'unknown'
|
126
|
+
@os_package_manager = OS_PACKAGE_MANAGERS[os_name] || 'unknown'
|
119
127
|
end
|
120
|
-
|
128
|
+
@os_package_manager
|
121
129
|
end
|
122
130
|
|
123
131
|
# Returns the set of known package managers
|
@@ -143,7 +151,7 @@ def initialize(defs = Hash.new, file = nil,
|
|
143
151
|
@prefer_indep_over_os_packages = false
|
144
152
|
@aliases = Hash.new
|
145
153
|
|
146
|
-
@sources
|
154
|
+
@sources = Hash.new
|
147
155
|
@installed_packages = Set.new
|
148
156
|
@operating_system = operating_system
|
149
157
|
@supported_operating_system = nil
|
@@ -195,57 +203,58 @@ def invalidate_resolve_package_cache
|
|
195
203
|
# takes precedence
|
196
204
|
def merge(info, suffixes: [])
|
197
205
|
@definitions = definitions.merge(info.definitions) do |h, v1, v2|
|
198
|
-
if v1 != v2
|
199
|
-
warn_about_merge_collisions(info, suffixes, h, v1, v2)
|
200
|
-
end
|
206
|
+
warn_about_merge_collisions(info, suffixes, h, v1, v2) if v1 != v2
|
201
207
|
v2
|
202
208
|
end
|
203
209
|
invalidate_resolve_package_cache
|
204
210
|
|
205
211
|
@sources = sources.merge(info.sources)
|
206
|
-
@all_definitions = all_definitions.
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
entry
|
212
|
+
@all_definitions = all_definitions.
|
213
|
+
merge(info.all_definitions) do |_package_name, all_defs, new_all_defs|
|
214
|
+
all_defs = all_defs.dup
|
215
|
+
new_all_defs = new_all_defs.dup
|
216
|
+
new_all_defs.delete_if do |files, data|
|
217
|
+
if (entry = all_defs.find { |_, d| d == data })
|
218
|
+
entry[0] |= files
|
219
|
+
end
|
212
220
|
end
|
221
|
+
all_defs.concat(new_all_defs)
|
213
222
|
end
|
214
|
-
all_defs.concat(new_all_defs)
|
215
|
-
end
|
216
223
|
end
|
217
224
|
|
218
225
|
# @api private
|
219
226
|
#
|
220
227
|
# Warn about a collision (override) detected during #merge
|
221
|
-
def warn_about_merge_collisions(merged_info, suffixes, key,
|
228
|
+
def warn_about_merge_collisions(merged_info, suffixes, key,
|
229
|
+
_old_value, _new_value)
|
222
230
|
old = source_of(key)
|
223
231
|
new = merged_info.source_of(key)
|
224
232
|
|
225
|
-
if suffixes.any? { |s| "#{old}#{s}"
|
226
|
-
return
|
227
|
-
end
|
233
|
+
return if suffixes.any? { |s| new == "#{old}#{s}" }
|
228
234
|
|
229
235
|
# Warn if the new osdep definition resolves to a different
|
230
236
|
# set of packages than the old one
|
231
|
-
old_resolved = resolve_package(key, resolve_recursive: false).
|
232
|
-
|
233
|
-
|
234
|
-
|
235
|
-
new_resolved = merged_info.resolve_package(key, resolve_recursive: false).
|
236
|
-
|
237
|
-
|
238
|
-
|
237
|
+
old_resolved = resolve_package(key, resolve_recursive: false).
|
238
|
+
each_with_object(Hash.new) do |(handler, status, list), osdep_h|
|
239
|
+
osdep_h[handler] = [status, list.dup]
|
240
|
+
end
|
241
|
+
new_resolved = merged_info.resolve_package(key, resolve_recursive: false).
|
242
|
+
each_with_object(Hash.new) do |(handler, status, list), osdep_h|
|
243
|
+
osdep_h[handler] = [status, list.dup]
|
244
|
+
end
|
239
245
|
if old_resolved != new_resolved
|
240
|
-
Autoproj.warn "osdeps definition for #{key},
|
246
|
+
Autoproj.warn "osdeps definition for #{key}, "\
|
247
|
+
"previously defined in #{old} overridden by #{new}:"
|
241
248
|
first = true
|
242
249
|
old_resolved.each do |handler, (_, packages)|
|
243
|
-
Autoproj.warn " #{first ? 'resp. ' : ' '}#{handler}:
|
250
|
+
Autoproj.warn " #{first ? 'resp. ' : ' '}#{handler}: "\
|
251
|
+
"#{packages.map(&:to_s).join(', ')}"
|
244
252
|
first = false
|
245
253
|
end
|
246
254
|
first = true
|
247
255
|
new_resolved.each do |handler, (_, packages)|
|
248
|
-
Autoproj.warn " #{first ? 'and ' : ' '}#{handler}:
|
256
|
+
Autoproj.warn " #{first ? 'and ' : ' '}#{handler}: "\
|
257
|
+
"#{packages.map(&:to_s).join(', ')}"
|
249
258
|
first = false
|
250
259
|
end
|
251
260
|
end
|
@@ -255,25 +264,27 @@ def warn_about_merge_collisions(merged_info, suffixes, key, old_value, new_value
|
|
255
264
|
def self.verify_definitions(hash, path = [])
|
256
265
|
hash.each do |key, value|
|
257
266
|
if value && !key.kind_of?(String)
|
258
|
-
raise ArgumentError, "invalid osdeps definition:
|
267
|
+
raise ArgumentError, "invalid osdeps definition: "\
|
268
|
+
"found an #{key.class} as a key in #{path.join('/')}. "\
|
269
|
+
"Don't forget to put quotes around numbers"
|
259
270
|
elsif !value && (key.kind_of?(Hash) || key.kind_of?(Array))
|
260
271
|
verify_definitions(key)
|
261
272
|
end
|
262
|
-
next
|
273
|
+
next unless value
|
263
274
|
|
264
275
|
if value.kind_of?(Array) || value.kind_of?(Hash)
|
265
276
|
verify_definitions(value, (path + [key]))
|
266
|
-
|
267
|
-
|
268
|
-
|
269
|
-
|
277
|
+
elsif !value.kind_of?(String)
|
278
|
+
raise ArgumentError, "invalid osdeps definition: "\
|
279
|
+
"found an #{value.class} as a value in #{path.join('/')}. "\
|
280
|
+
"Don't forget to put quotes around numbers"
|
270
281
|
end
|
271
282
|
end
|
272
283
|
end
|
273
284
|
|
274
285
|
# Whether the operating system could be autodetected successfully
|
275
286
|
def known_operating_system?
|
276
|
-
os_names,
|
287
|
+
os_names, = operating_system
|
277
288
|
!os_names.empty?
|
278
289
|
end
|
279
290
|
|
@@ -283,24 +294,20 @@ def supported_operating_system?
|
|
283
294
|
if @supported_operating_system.nil?
|
284
295
|
@supported_operating_system = (os_package_manager != 'unknown')
|
285
296
|
end
|
286
|
-
|
297
|
+
@supported_operating_system
|
287
298
|
end
|
288
299
|
|
289
300
|
def self.guess_operating_system
|
290
301
|
if File.exist?('/etc/debian_version')
|
291
302
|
versions = [File.read('/etc/debian_version').strip]
|
292
|
-
if versions.first =~ /sid/
|
293
|
-
versions = ["unstable", "sid"]
|
294
|
-
end
|
303
|
+
versions = %w[unstable sid] if versions.first =~ /sid/
|
295
304
|
[['debian'], versions]
|
296
305
|
elsif File.exist?('/etc/redhat-release')
|
297
306
|
release_string = File.read('/etc/redhat-release').strip
|
298
307
|
release_string =~ /(.*) release ([\d.]+)/
|
299
308
|
name = $1.downcase
|
300
309
|
version = $2
|
301
|
-
if name =~ /Red Hat Entreprise/
|
302
|
-
name = 'rhel'
|
303
|
-
end
|
310
|
+
name = 'rhel' if name =~ /Red Hat Entreprise/
|
304
311
|
[[name], [version]]
|
305
312
|
elsif File.exist?('/etc/gentoo-release')
|
306
313
|
release_string = File.read('/etc/gentoo-release').strip
|
@@ -309,19 +316,19 @@ def self.guess_operating_system
|
|
309
316
|
[['gentoo'], [version]]
|
310
317
|
elsif File.exist?('/etc/arch-release')
|
311
318
|
[['arch'], []]
|
312
|
-
elsif Autobuild.macos?
|
313
|
-
version
|
319
|
+
elsif Autobuild.macos?
|
320
|
+
version = `sw_vers | head -2 | tail -1`.split(":")[1]
|
314
321
|
manager =
|
315
|
-
|
316
|
-
|
317
|
-
|
318
|
-
end
|
319
|
-
if !OS_PACKAGE_MANAGERS.has_key?(manager)
|
322
|
+
ENV['AUTOPROJ_MACOSX_PACKAGE_MANAGER'] ||
|
323
|
+
'macos-brew'
|
324
|
+
unless OS_PACKAGE_MANAGERS.key?(manager)
|
320
325
|
known_managers = OS_PACKAGE_MANAGERS.keys.grep(/^macos/)
|
321
|
-
raise ArgumentError, "#{manager} is not a known MacOSX
|
326
|
+
raise ArgumentError, "#{manager} is not a known MacOSX "\
|
327
|
+
"package manager. Known package managers are "\
|
328
|
+
"#{known_managers.join(', ')}"
|
322
329
|
end
|
323
330
|
|
324
|
-
managers =
|
331
|
+
managers =
|
325
332
|
if manager == 'macos-port'
|
326
333
|
[manager, 'port']
|
327
334
|
else [manager]
|
@@ -331,12 +338,12 @@ def self.guess_operating_system
|
|
331
338
|
[['windows'], []]
|
332
339
|
elsif File.exist?('/etc/SuSE-release')
|
333
340
|
version = File.read('/etc/SuSE-release').strip
|
334
|
-
version
|
341
|
+
version =~ /.*VERSION\s+=\s+([^\s]+)/
|
335
342
|
version = $1
|
336
343
|
[['opensuse'], [version.strip]]
|
337
|
-
elsif Autobuild.freebsd?
|
338
|
-
|
339
|
-
|
344
|
+
elsif Autobuild.freebsd?
|
345
|
+
version = `uname -r`.strip.split("-")[0]
|
346
|
+
[['freebsd'], [version]]
|
340
347
|
end
|
341
348
|
end
|
342
349
|
|
@@ -349,21 +356,17 @@ def self.ensure_derivatives_refer_to_their_parents(names)
|
|
349
356
|
'/etc/arch-release' => 'arch',
|
350
357
|
'/etc/SuSE-release' => 'opensuse']
|
351
358
|
version_files.each do |file, name|
|
352
|
-
if File.exist?(file) && !names.include?(name)
|
353
|
-
names << name
|
354
|
-
end
|
359
|
+
names << name if File.exist?(file) && !names.include?(name)
|
355
360
|
end
|
356
361
|
names
|
357
362
|
end
|
358
|
-
|
363
|
+
|
359
364
|
def self.normalize_os_representation(names, versions)
|
360
365
|
# Normalize the names to lowercase
|
361
366
|
names = names.map(&:downcase)
|
362
367
|
versions = versions.map(&:downcase)
|
363
|
-
|
364
|
-
|
365
|
-
end
|
366
|
-
return names, versions
|
368
|
+
versions += ['default'] unless versions.include?('default')
|
369
|
+
[names, versions]
|
367
370
|
end
|
368
371
|
|
369
372
|
# The operating system self is targetting
|
@@ -392,20 +395,18 @@ def operating_system=(values)
|
|
392
395
|
#
|
393
396
|
# Examples: ['debian', ['sid', 'unstable']] or ['ubuntu', ['lucid lynx', '10.04']]
|
394
397
|
def self.autodetect_operating_system
|
395
|
-
if user_os = ENV['AUTOPROJ_OS']
|
398
|
+
if (user_os = ENV['AUTOPROJ_OS'])
|
396
399
|
if user_os.empty?
|
397
400
|
return false
|
398
401
|
else
|
399
402
|
names, versions = user_os.split(':')
|
400
|
-
return normalize_os_representation(
|
403
|
+
return normalize_os_representation(
|
404
|
+
names.split(','), versions.split(','))
|
401
405
|
end
|
402
406
|
end
|
403
407
|
|
404
408
|
names, versions = os_from_os_release
|
405
|
-
|
406
|
-
if !names
|
407
|
-
names, versions = guess_operating_system
|
408
|
-
end
|
409
|
+
names, versions = guess_operating_system unless names
|
409
410
|
|
410
411
|
# on Debian, they refuse to put enough information to detect
|
411
412
|
# 'unstable' reliably. So, we use the heuristic method for it
|
@@ -416,21 +417,19 @@ def self.autodetect_operating_system
|
|
416
417
|
# phase...
|
417
418
|
if File.exist?('/etc/debian_version')
|
418
419
|
debian_versions = [File.read('/etc/debian_version').strip]
|
419
|
-
if debian_versions.first =~ /sid/
|
420
|
-
versions = ["unstable", "sid"]
|
421
|
-
end
|
420
|
+
versions = %w[unstable sid] if debian_versions.first =~ /sid/
|
422
421
|
end
|
423
422
|
# otherwise "versions" contains the result it previously had
|
424
423
|
end
|
425
|
-
return
|
424
|
+
return unless names
|
426
425
|
|
427
426
|
names = ensure_derivatives_refer_to_their_parents(names)
|
428
427
|
names, versions = normalize_os_representation(names, versions)
|
429
|
-
|
428
|
+
[names, versions]
|
430
429
|
end
|
431
430
|
|
432
431
|
def self.os_from_os_release(filename = '/etc/os-release')
|
433
|
-
return
|
432
|
+
return unless File.exist?(filename)
|
434
433
|
|
435
434
|
fields = Hash.new
|
436
435
|
File.readlines(filename).each do |line|
|
@@ -438,7 +437,8 @@ def self.os_from_os_release(filename = '/etc/os-release')
|
|
438
437
|
if line.strip =~ /^(\w+)=(?:["'])?([^"']+)(?:["'])?$/
|
439
438
|
fields[$1] = $2
|
440
439
|
elsif !line.empty?
|
441
|
-
Autoproj.warn "could not parse line '#{line.inspect}'
|
440
|
+
Autoproj.warn "could not parse line '#{line.inspect}' "\
|
441
|
+
"in /etc/os-release"
|
442
442
|
end
|
443
443
|
end
|
444
444
|
|
@@ -448,19 +448,17 @@ def self.os_from_os_release(filename = '/etc/os-release')
|
|
448
448
|
versions << fields['VERSION_ID']
|
449
449
|
version = fields['VERSION'] || ''
|
450
450
|
versions.concat(version.gsub(/[^\w.]/, ' ').split(' '))
|
451
|
-
|
451
|
+
[names.compact.uniq, versions.compact.uniq]
|
452
452
|
end
|
453
453
|
|
454
454
|
def self.os_from_lsb
|
455
|
-
|
456
|
-
return
|
457
|
-
end
|
455
|
+
return unless Autobuild.find_in_path('lsb_release')
|
458
456
|
|
459
457
|
distributor = [`lsb_release -i -s`.strip.downcase]
|
460
458
|
codename = `lsb_release -c -s`.strip.downcase
|
461
459
|
version = `lsb_release -r -s`.strip.downcase
|
462
460
|
|
463
|
-
|
461
|
+
[distributor, [codename, version]]
|
464
462
|
end
|
465
463
|
|
466
464
|
class InvalidRecursiveStatement < Autobuild::Exception; end
|
@@ -471,8 +469,8 @@ class InvalidRecursiveStatement < Autobuild::Exception; end
|
|
471
469
|
# returns an array contain the path starting with name and
|
472
470
|
# ending at the resolved name
|
473
471
|
def resolve_name(name)
|
474
|
-
path = [
|
475
|
-
while aliases.
|
472
|
+
path = [name]
|
473
|
+
while aliases.key?(name)
|
476
474
|
name = aliases[name]
|
477
475
|
path << name
|
478
476
|
end
|
@@ -482,7 +480,9 @@ def resolve_name(name)
|
|
482
480
|
# Null object class that is used to mark recursive resolution when
|
483
481
|
# calling {#resolve_package} with resolve_recursive set to false
|
484
482
|
class OSDepRecursiveResolver
|
485
|
-
def self.to_s
|
483
|
+
def self.to_s
|
484
|
+
'osdep'.freeze
|
485
|
+
end
|
486
486
|
end
|
487
487
|
|
488
488
|
# Return the list of packages that should be installed for +name+
|
@@ -503,17 +503,13 @@ def self.to_s; 'osdep' end
|
|
503
503
|
# name and version. The package list might be empty even if status ==
|
504
504
|
# FOUND_PACKAGES, for instance if the ignore keyword is used.
|
505
505
|
def resolve_package(name, resolve_recursive: true)
|
506
|
-
if resolve_package_cache.
|
507
|
-
return resolve_package_cache[name]
|
508
|
-
end
|
506
|
+
return resolve_package_cache[name] if resolve_package_cache.key?(name)
|
509
507
|
|
510
508
|
path = resolve_name(name)
|
511
509
|
name = path.last
|
512
510
|
|
513
511
|
dep_def = definitions[name]
|
514
|
-
|
515
|
-
return (resolve_package_cache[name] = nil)
|
516
|
-
end
|
512
|
+
return (resolve_package_cache[name] = nil) unless dep_def
|
517
513
|
|
518
514
|
os_names, os_versions = operating_system
|
519
515
|
|
@@ -534,27 +530,28 @@ def resolve_package(name, resolve_recursive: true)
|
|
534
530
|
end
|
535
531
|
|
536
532
|
result = []
|
537
|
-
found, pkg = partition_osdep_entry(
|
538
|
-
|
539
|
-
|
540
|
-
|
541
|
-
end
|
533
|
+
found, pkg = partition_osdep_entry(
|
534
|
+
name, dep_def, nil,
|
535
|
+
(package_managers - [os_package_manager]), os_names, os_versions)
|
536
|
+
result << [os_package_manager, found, pkg] if found
|
542
537
|
|
543
538
|
package_managers.each do |handler|
|
544
|
-
found, pkg = partition_osdep_entry(
|
545
|
-
|
546
|
-
|
547
|
-
end
|
539
|
+
found, pkg = partition_osdep_entry(
|
540
|
+
name, dep_def, [handler], [], os_names, os_versions)
|
541
|
+
result << [handler, found, pkg] if found
|
548
542
|
end
|
549
543
|
|
550
544
|
# Recursive resolutions
|
551
|
-
found, pkg = partition_osdep_entry(
|
545
|
+
found, pkg = partition_osdep_entry(
|
546
|
+
name, dep_def, ['osdep'], [], os_names, os_versions)
|
552
547
|
if found
|
553
548
|
if resolve_recursive
|
554
549
|
pkg.each do |pkg_name|
|
555
550
|
resolved = resolve_package(pkg_name)
|
556
|
-
|
557
|
-
raise InvalidRecursiveStatement, "the '#{name}' osdep
|
551
|
+
unless resolved
|
552
|
+
raise InvalidRecursiveStatement, "the '#{name}' osdep "\
|
553
|
+
"refers to another osdep, '#{pkg_name}', which "\
|
554
|
+
"does not seem to exist"
|
558
555
|
end
|
559
556
|
result.concat(resolved)
|
560
557
|
end
|
@@ -641,66 +638,20 @@ def partition_osdep_entry(osdep_name, dep_def, handler_names, excluded, *keys)
|
|
641
638
|
found_keys = Hash.new
|
642
639
|
Array(dep_def).each do |names, values|
|
643
640
|
if !values
|
644
|
-
|
645
|
-
|
646
|
-
|
647
|
-
found = true if !handler_names
|
648
|
-
elsif names == 'nonexistent'
|
649
|
-
nonexistent = true if !handler_names
|
650
|
-
elsif !handler_names && names.kind_of?(Array)
|
651
|
-
result.concat(result)
|
652
|
-
found = true
|
653
|
-
elsif names.respond_to?(:to_str)
|
654
|
-
if excluded.include?(names)
|
655
|
-
elsif handler_names && handler_names.include?(names)
|
656
|
-
result << osdep_name
|
657
|
-
found = true
|
658
|
-
elsif !handler_names
|
659
|
-
result << names
|
660
|
-
found = true
|
661
|
-
end
|
662
|
-
elsif names.respond_to?(:to_hash)
|
663
|
-
rec_found, rec_result = partition_osdep_entry(osdep_name, names, handler_names, excluded, keys, *additional_keys)
|
664
|
-
if rec_found == FOUND_NONEXISTENT then nonexistent = true
|
665
|
-
elsif rec_found == FOUND_PACKAGES then found = true
|
666
|
-
end
|
667
|
-
result.concat(rec_result)
|
668
|
-
end
|
641
|
+
entry_found, entry_nonexistent, entry_names =
|
642
|
+
partition_osdep_raw_array_entry(names, osdep_name,
|
643
|
+
handler_names, excluded, keys, additional_keys)
|
669
644
|
else
|
670
|
-
|
671
|
-
names
|
672
|
-
|
673
|
-
|
674
|
-
if handler_names
|
675
|
-
if matching_name = handler_names.find { |k| names.any? { |name_tag| k == name_tag.downcase } }
|
676
|
-
rec_found, rec_result = partition_osdep_entry(osdep_name, values, nil, excluded, keys, *additional_keys)
|
677
|
-
if rec_found == FOUND_NONEXISTENT then nonexistent = true
|
678
|
-
elsif rec_found == FOUND_PACKAGES then found = true
|
679
|
-
end
|
680
|
-
result.concat(rec_result)
|
681
|
-
end
|
682
|
-
end
|
683
|
-
|
684
|
-
matching_name = keys.find { |k| names.any? { |name_tag| k == name_tag.downcase } }
|
685
|
-
if matching_name
|
686
|
-
rec_found, rec_result = partition_osdep_entry(osdep_name, values, handler_names, excluded, *additional_keys)
|
687
|
-
# We only consider the first highest-priority entry,
|
688
|
-
# regardless of whether it has some packages for us or
|
689
|
-
# not
|
690
|
-
idx = keys.index(matching_name)
|
691
|
-
if !rec_found
|
692
|
-
if !found_keys.has_key?(idx)
|
693
|
-
found_keys[idx] = nil
|
694
|
-
end
|
695
|
-
else
|
696
|
-
found_keys[idx] ||= [0, []]
|
697
|
-
found_keys[idx][0] += rec_found
|
698
|
-
found_keys[idx][1].concat(rec_result)
|
699
|
-
end
|
700
|
-
end
|
645
|
+
entry_found, entry_nonexistent, entry_names =
|
646
|
+
partition_osdep_map_entry(names, values, osdep_name,
|
647
|
+
handler_names, excluded, keys, found_keys, additional_keys)
|
701
648
|
end
|
649
|
+
found ||= entry_found
|
650
|
+
nonexistent ||= entry_nonexistent
|
651
|
+
result.concat(entry_names)
|
702
652
|
end
|
703
|
-
|
653
|
+
|
654
|
+
first_entry = found_keys.keys.min
|
704
655
|
found_keys = found_keys[first_entry]
|
705
656
|
if found_keys
|
706
657
|
if found_keys[0] > 0
|
@@ -717,13 +668,91 @@ def partition_osdep_entry(osdep_name, dep_def, handler_names, excluded, *keys)
|
|
717
668
|
else false
|
718
669
|
end
|
719
670
|
|
720
|
-
|
671
|
+
[found, result]
|
672
|
+
end
|
673
|
+
|
674
|
+
def partition_osdep_raw_array_entry(names, osdep_name, handler_names,
|
675
|
+
excluded, keys, additional_keys)
|
676
|
+
have_handler_names = true if handler_names
|
677
|
+
|
678
|
+
# Raw array of packages. Possible only if we are not at toplevel
|
679
|
+
# (i.e. if we already have a handler)
|
680
|
+
if names == 'ignore'
|
681
|
+
[!have_handler_names, false, []]
|
682
|
+
elsif names == 'nonexistent'
|
683
|
+
[false, !have_handler_names, []]
|
684
|
+
elsif !handler_names && names.kind_of?(Array)
|
685
|
+
[true, false, names]
|
686
|
+
elsif names.respond_to?(:to_str)
|
687
|
+
if excluded.include?(names)
|
688
|
+
[false, false, []]
|
689
|
+
elsif handler_names&.include?(names)
|
690
|
+
[true, false, [osdep_name]]
|
691
|
+
elsif !handler_names
|
692
|
+
[true, false, [names]]
|
693
|
+
else
|
694
|
+
[false, false, []]
|
695
|
+
end
|
696
|
+
elsif names.respond_to?(:to_hash)
|
697
|
+
rec_found, rec_result = partition_osdep_entry(osdep_name,
|
698
|
+
names, handler_names, excluded, keys, *additional_keys)
|
699
|
+
if rec_found == FOUND_NONEXISTENT
|
700
|
+
[false, true, rec_result]
|
701
|
+
elsif rec_found == FOUND_PACKAGES
|
702
|
+
[true, false, rec_result]
|
703
|
+
else
|
704
|
+
[false, false, []]
|
705
|
+
end
|
706
|
+
else
|
707
|
+
[false, false, []]
|
708
|
+
end
|
709
|
+
end
|
710
|
+
|
711
|
+
def partition_osdep_map_entry(names, values, osdep_name, handler_names,
|
712
|
+
excluded, keys, found_keys, additional_keys)
|
713
|
+
# names could be an array already
|
714
|
+
names = names.split(',') if names.respond_to?(:to_str)
|
715
|
+
result = [false, false, []]
|
716
|
+
|
717
|
+
if handler_names
|
718
|
+
matching_handler = handler_names.
|
719
|
+
find { |k| names.any? { |name_tag| k == name_tag.downcase } }
|
720
|
+
if matching_handler
|
721
|
+
rec_found, rec_result = partition_osdep_entry(
|
722
|
+
osdep_name, values, nil, excluded, keys, *additional_keys)
|
723
|
+
if rec_found == FOUND_NONEXISTENT
|
724
|
+
result = [false, true, rec_result]
|
725
|
+
elsif rec_found == FOUND_PACKAGES
|
726
|
+
result = [true, false, rec_result]
|
727
|
+
end
|
728
|
+
end
|
729
|
+
end
|
730
|
+
|
731
|
+
matching_name = keys.
|
732
|
+
find { |k| names.any? { |name_tag| k == name_tag.downcase } }
|
733
|
+
return result unless matching_name
|
734
|
+
|
735
|
+
rec_found, rec_result = partition_osdep_entry(
|
736
|
+
osdep_name, values, handler_names, excluded, *additional_keys)
|
737
|
+
# We only consider the first highest-priority entry,
|
738
|
+
# regardless of whether it has some packages for us or
|
739
|
+
# not
|
740
|
+
idx = keys.index(matching_name)
|
741
|
+
if !rec_found
|
742
|
+
found_keys[idx] = nil unless found_keys.key?(idx)
|
743
|
+
else
|
744
|
+
found_keys[idx] ||= [0, []]
|
745
|
+
found_keys[idx][0] += rec_found
|
746
|
+
found_keys[idx][1].concat(rec_result)
|
747
|
+
end
|
748
|
+
result
|
721
749
|
end
|
722
750
|
|
723
751
|
# Resolves the given OS dependencies into the actual packages that need
|
724
752
|
# to be installed on this particular OS.
|
725
753
|
#
|
726
|
-
# @param [Array<String>] dependencies the list of osdep names that
|
754
|
+
# @param [Array<String>] dependencies the list of osdep names that
|
755
|
+
# should be resolved
|
727
756
|
# @return [Array<#install,Array<String>>] the set of packages, grouped
|
728
757
|
# by the package handlers that should be used to install them
|
729
758
|
#
|
@@ -733,25 +762,33 @@ def resolve_os_packages(dependencies)
|
|
733
762
|
all_packages = []
|
734
763
|
dependencies.each do |name|
|
735
764
|
result = resolve_package(name)
|
736
|
-
|
765
|
+
unless result
|
737
766
|
path = resolve_name(name)
|
738
|
-
raise MissingOSDep.new, "there is no osdeps definition
|
767
|
+
raise MissingOSDep.new, "there is no osdeps definition "\
|
768
|
+
"for #{path.last} (search tree: #{path.join('->')})"
|
739
769
|
end
|
740
770
|
|
741
771
|
if result.empty?
|
742
772
|
os_names, os_versions = operating_system
|
743
773
|
if os_names.empty?
|
744
|
-
raise MissingOSDep.new, "there is an osdeps
|
774
|
+
raise MissingOSDep.new, "there is an osdeps "\
|
775
|
+
"definition for #{name}, but autoproj cannot "\
|
776
|
+
"detect the local operation system"
|
745
777
|
else
|
746
|
-
raise MissingOSDep.new, "there is an osdeps
|
778
|
+
raise MissingOSDep.new, "there is an osdeps "\
|
779
|
+
"definition for #{name}, but not for this "\
|
780
|
+
"operating system and version resp. "\
|
781
|
+
"#{os_names.join(', ')} and #{os_versions.join(', ')})"
|
747
782
|
end
|
748
783
|
end
|
749
784
|
|
750
785
|
result.each do |handler, status, packages|
|
751
786
|
if status == FOUND_NONEXISTENT
|
752
|
-
raise MissingOSDep.new, "there is an osdep
|
787
|
+
raise MissingOSDep.new, "there is an osdep "\
|
788
|
+
"definition for #{name}, and it explicitely "\
|
789
|
+
"states that this package does not exist on your OS"
|
753
790
|
end
|
754
|
-
if entry = all_packages.find { |h, _| h == handler }
|
791
|
+
if (entry = all_packages.find { |h, _| h == handler })
|
755
792
|
entry[1].concat(packages)
|
756
793
|
else
|
757
794
|
all_packages << [handler, packages.dup]
|
@@ -759,22 +796,22 @@ def resolve_os_packages(dependencies)
|
|
759
796
|
end
|
760
797
|
end
|
761
798
|
|
762
|
-
all_packages.delete_if do |
|
799
|
+
all_packages.delete_if do |_handler, pkg|
|
763
800
|
pkg.empty?
|
764
801
|
end
|
765
|
-
|
802
|
+
all_packages
|
766
803
|
end
|
767
804
|
|
768
805
|
# Returns true if the given name has an entry in the osdeps
|
769
806
|
def include?(name)
|
770
|
-
definitions.
|
807
|
+
definitions.key?(name)
|
771
808
|
end
|
772
809
|
|
773
810
|
# Returns true if +name+ is an acceptable OS package for this OS and
|
774
811
|
# version
|
775
812
|
def has?(name)
|
776
813
|
status = availability_of(name)
|
777
|
-
|
814
|
+
[AVAILABLE, IGNORE].include?(status)
|
778
815
|
end
|
779
816
|
|
780
817
|
# Value returned by #availability_of if the required package has no
|
@@ -809,9 +846,7 @@ def has?(name)
|
|
809
846
|
# be installed for it
|
810
847
|
def availability_of(name)
|
811
848
|
resolved = resolve_package(name)
|
812
|
-
|
813
|
-
return NO_PACKAGE
|
814
|
-
end
|
849
|
+
return NO_PACKAGE unless resolved
|
815
850
|
|
816
851
|
if resolved.empty?
|
817
852
|
if known_operating_system?
|
@@ -821,7 +856,9 @@ def availability_of(name)
|
|
821
856
|
end
|
822
857
|
end
|
823
858
|
|
824
|
-
resolved = resolved.find_all
|
859
|
+
resolved = resolved.find_all do |_, status, list|
|
860
|
+
status != FOUND_PACKAGES || !list.empty?
|
861
|
+
end
|
825
862
|
failed = resolved.find_all do |_, status, _|
|
826
863
|
status == FOUND_NONEXISTENT
|
827
864
|
end
|
@@ -837,4 +874,3 @@ def availability_of(name)
|
|
837
874
|
end
|
838
875
|
end
|
839
876
|
end
|
840
|
-
|