autoproj 1.7.21.b1 → 1.7.21.b2

Sign up to get free protection for your applications and to get access to all the features.
@@ -8,9 +8,9 @@ ruby18:
8
8
  - rubygems1.8
9
9
  - ri1.8
10
10
  - libopenssl-ruby1.8
11
+ - rake
11
12
  gentoo:
12
13
  - dev-lang/ruby:1.8
13
- gem:
14
14
  - rake
15
15
 
16
16
  ruby19:
@@ -18,6 +18,7 @@ ruby19:
18
18
  - ruby1.9.1
19
19
  - ruby1.9.1-dev
20
20
  - rubygems1.9.1
21
+ - rake
21
22
 
22
23
  ubuntu:
23
24
  - ruby1.9.1
@@ -25,11 +26,12 @@ ruby19:
25
26
  - rubygems1.9.1
26
27
  - ri1.9.1
27
28
  - libopenssl-ruby1.9.1
29
+ - rake
28
30
  gentoo:
29
31
  - dev-lang/ruby:1.9
32
+ - rake
30
33
  arch:
31
34
  - ruby
32
- gem:
33
35
  - rake
34
36
 
35
37
  build-essential:
@@ -1709,8 +1709,7 @@ module Autoproj
1709
1709
  # a proper error message.
1710
1710
  if !available_as_source
1711
1711
  begin
1712
- osdeps, gems = Autoproj.osdeps.partition_packages([name].to_set)
1713
- Autoproj.osdeps.resolve_os_dependencies(osdeps)
1712
+ Autoproj.osdeps.resolve_os_dependencies([name].to_set)
1714
1713
  rescue Autoproj::ConfigError => e
1715
1714
  if osdeps_availability != Autoproj::OSDependencies::NO_PACKAGE && !Autoproj.osdeps.installs_os_packages?
1716
1715
  Autoproj.warn "in #{File.join(srcdir, 'manifest.xml')}: #{e.message}"
@@ -1,5 +1,373 @@
1
1
  require 'tempfile'
2
2
  module Autoproj
3
+ # Module that contains the package manager implementations for the
4
+ # OSDependencies class
5
+ module PackageManagers
6
+ # Base class for all package managers. Subclasses must add the
7
+ # #install(packages) method and may add the
8
+ # #filter_uptodate_packages(packages) method
9
+ class Manager
10
+ attr_reader :names
11
+
12
+ attr_writer :enabled
13
+ def enabled?; !!@enabled end
14
+
15
+ attr_writer :silent
16
+ def silent?; !!@silent end
17
+
18
+ def initialize(names = [])
19
+ @names = names.dup
20
+ @enabled = true
21
+ @silent = true
22
+ end
23
+ end
24
+
25
+ # Dummy package manager used for unknown OSes. It simply displays a
26
+ # message to the user when packages are needed
27
+ class UnknownOSManager < Manager
28
+ def osdeps_interaction_unknown_os(osdeps)
29
+ puts <<-EOMSG
30
+ #{Autoproj.color("The build process requires some other software packages to be installed on our operating system", :bold)}
31
+ #{Autoproj.color("If they are already installed, simply ignore this message", :red)}
32
+
33
+ #{osdeps.join("\n ")}
34
+
35
+ EOMSG
36
+ print Autoproj.color("Press ENTER to continue", :bold)
37
+ STDOUT.flush
38
+ STDIN.readline
39
+ puts
40
+ nil
41
+ end
42
+
43
+
44
+ def install(osdeps)
45
+ if silent?
46
+ return false
47
+ else
48
+ return osdeps_interaction_unknown_os(osdeps)
49
+ end
50
+ end
51
+ end
52
+
53
+ # Base class for all package managers that simply require the call of a
54
+ # shell script to install packages (e.g. yum, apt, ...)
55
+ class ShellScriptManager < Manager
56
+ def self.execute_as_root(script, with_locking)
57
+ if with_locking
58
+ File.open('/tmp/autoproj_osdeps_lock', 'w') do |lock_io|
59
+ begin
60
+ while !lock_io.flock(File::LOCK_EX | File::LOCK_NB)
61
+ Autoproj.message " waiting for other autoproj instances to finish their osdeps installation"
62
+ sleep 5
63
+ end
64
+ return execute_as_root(script, false)
65
+ ensure
66
+ lock_io.flock(File::LOCK_UN)
67
+ end
68
+ end
69
+ end
70
+
71
+
72
+ Tempfile.open('osdeps_sh') do |io|
73
+ io.puts "#! /bin/bash"
74
+ io.puts GAIN_ROOT_ACCESS
75
+ io.write script
76
+ io.flush
77
+ Autobuild::Subprocess.run 'autoproj', 'osdeps', '/bin/bash', io.path
78
+ end
79
+ end
80
+
81
+ GAIN_ROOT_ACCESS = <<-EOSCRIPT
82
+ # Gain root access using sudo
83
+ if test `id -u` != "0"; then
84
+ exec sudo /bin/bash $0 "$@"
85
+
86
+ fi
87
+ EOSCRIPT
88
+
89
+ attr_writer :needs_locking
90
+ def needs_locking?; !!@needs_locking end
91
+
92
+ def initialize(names, needs_locking, user_install_cmd, auto_install_cmd)
93
+ super(names)
94
+ @needs_locking, @user_install_cmd, @auto_install_cmd =
95
+ needs_locking, user_install_cmd, auto_install_cmd
96
+ end
97
+
98
+ def generate_user_os_script(os_packages)
99
+ if user_install_cmd
100
+ (user_install_cmd % [os_packages.join("' '")])
101
+ else generate_auto_os_script(os_packages)
102
+ end
103
+ end
104
+
105
+ def generate_auto_os_script(os_packages)
106
+ (auto_install_cmd % [os_packages.join("' '")])
107
+ end
108
+
109
+ def osdeps_interaction(osdeps, os_packages, shell_script)
110
+ if OSDependencies.force_osdeps
111
+ return true
112
+ elsif enabled?
113
+ return true
114
+ elsif silent?
115
+ return false
116
+ end
117
+
118
+ # We're asked to not install the OS packages but to display them
119
+ # anyway, do so now
120
+ puts <<-EOMSG
121
+
122
+ #{Autoproj.color("The build process and/or the packages require some other software to be installed", :bold)}
123
+ #{Autoproj.color("and you required autoproj to not install them itself", :bold)}
124
+ #{Autoproj.color("\nIf these packages are already installed, simply ignore this message\n", :red) if !respond_to?(:filter_uptodate_packages)}
125
+ The following packages are available as OS dependencies, i.e. as prebuilt
126
+ packages provided by your distribution / operating system. You will have to
127
+ install them manually if they are not already installed
128
+
129
+ #{os_packages.sort.join("\n ")}
130
+
131
+ the following command line(s) can be run as root to install them:
132
+
133
+ #{shell_script.split("\n").join("\n| ")}
134
+
135
+ EOMSG
136
+ print " #{Autoproj.color("Press ENTER to continue ", :bold)}"
137
+ STDOUT.flush
138
+ STDIN.readline
139
+ puts
140
+ false
141
+ end
142
+
143
+ def install(packages)
144
+ handled_os = OSDependencies.supported_operating_system?
145
+ if handled_os
146
+ shell_script = generate_auto_os_script(os_packages)
147
+ user_shell_script = generate_user_os_script(os_packages)
148
+ end
149
+ if osdeps_interaction(osdeps, os_packages, user_shell_script)
150
+ Autoproj.message " installing OS packages: #{os_packages.sort.join(", ")}"
151
+
152
+ if Autoproj.verbose
153
+ Autoproj.message "Generating installation script for non-ruby OS dependencies"
154
+ Autoproj.message shell_script
155
+ end
156
+ ShellScriptManager.execute_as_root(shell_script, needs_locking?)
157
+ return true
158
+ end
159
+ false
160
+ end
161
+ end
162
+
163
+ # Package manager interface for systems that use APT and dpkg for
164
+ # package management
165
+ class AptDpkgManager < ShellScriptManager
166
+ def initialize
167
+ super(['apt-dpkg'], true,
168
+ "apt-get install '%s'",
169
+ "export DEBIAN_FRONTEND=noninteractive; apt-get install -y '%s'")
170
+ end
171
+
172
+ # On a dpkg-enabled system, checks if the provided package is installed
173
+ # and returns true if it is the case
174
+ def installed?(package_name)
175
+ if !@installed_packages
176
+ @installed_packages = Set.new
177
+ dpkg_status = File.readlines('/var/lib/dpkg/status')
178
+
179
+ current_packages = []
180
+ is_installed = false
181
+ dpkg_status.each do |line|
182
+ line = line.chomp
183
+ if line == ""
184
+ if is_installed
185
+ current_packages.each do |pkg|
186
+ @installed_packages << pkg
187
+ end
188
+ current_packages.clear
189
+ is_installed = false
190
+ end
191
+ elsif line =~ /Package: (.*)$/
192
+ current_packages << $1
193
+ elsif line =~ /Provides: (.*)$/
194
+ current_packages.concat($1.split(',').map(&:strip))
195
+ elsif line == "Status: install ok installed"
196
+ is_installed = true
197
+ end
198
+ end
199
+ end
200
+
201
+ if package_name =~ /^(\w[a-z0-9+-.]+)/
202
+ @installed_packages.include?($1)
203
+ else
204
+ Autoproj.warn "#{package_name} is not a valid Debian package name"
205
+ false
206
+ end
207
+ end
208
+
209
+ def filter_uptodate_packages(packages)
210
+ packages.find_all do |package_name|
211
+ !installed?(package_name)
212
+ end
213
+ end
214
+ end
215
+
216
+ # Package manager interface for the RubyGems system
217
+ class GemManager < Manager
218
+ class << self
219
+ attr_accessor :with_prerelease
220
+ attr_accessor :with_doc
221
+ end
222
+ @with_prerelease = false
223
+ @with_doc = false
224
+
225
+ def initialize
226
+ super(['gem'])
227
+ end
228
+
229
+ # Used to override the Gem::SpecFetcher object used by this gem
230
+ # manager. Useful mainly for testing
231
+ attr_writer :gem_fetcher
232
+
233
+ def gem_fetcher
234
+ if !@gem_fetcher
235
+ Autoproj.message "looking for RubyGems updates"
236
+ @gem_fetcher = Gem::SpecFetcher.fetcher
237
+ end
238
+ @gem_fetcher
239
+ end
240
+
241
+ def guess_gem_program
242
+ if Autobuild.programs['gem']
243
+ return Autobuild.programs['gem']
244
+ end
245
+
246
+ ruby_bin = Config::CONFIG['RUBY_INSTALL_NAME']
247
+ if ruby_bin =~ /^ruby(.+)$/
248
+ Autobuild.programs['gem'] = "gem#{$1}"
249
+ else
250
+ Autobuild.programs['gem'] = "gem"
251
+ end
252
+ end
253
+
254
+ def install(gems)
255
+ guess_gem_program
256
+
257
+ base_cmdline = [Autobuild.tool('gem'), 'install']
258
+ if !GemManager.with_doc
259
+ base_cmdline << '--no-rdoc' << '--no-ri'
260
+ end
261
+
262
+ if GemManager.with_prerelease
263
+ base_cmdline << "--prerelease"
264
+ end
265
+ with_version, without_version = gems.partition { |name, v| v }
266
+
267
+ cmdlines = []
268
+ if !without_version.empty?
269
+ cmdlines << (base_cmdline + without_version.flatten)
270
+ end
271
+ with_version.each do |name, v|
272
+ cmdlines << base_cmdline + [name, "-v", v]
273
+ end
274
+
275
+ if gems_interaction(gems, cmdlines)
276
+ Autoproj.message "installing/updating RubyGems dependencies: #{gems.map { |g| g.join(" ") }.sort.join(", ")}"
277
+
278
+ cmdlines.each do |c|
279
+ Autobuild::Subprocess.run 'autoproj', 'osdeps', *c
280
+ end
281
+ did_something = true
282
+ end
283
+ end
284
+
285
+ # Returns the set of RubyGem packages in +packages+ that are not already
286
+ # installed, or that can be upgraded
287
+ def filter_uptodate_packages(gems)
288
+ # Don't install gems that are already there ...
289
+ gems = gems.dup
290
+ gems.delete_if do |name, version|
291
+ version_requirements = Gem::Requirement.new(version || '>= 0')
292
+ installed =
293
+ if Gem::Specification.respond_to?(:find_by_name)
294
+ begin
295
+ [Gem::Specification.find_by_name(name, version_requirements)]
296
+ rescue Gem::LoadError
297
+ []
298
+ end
299
+ else
300
+ Gem.source_index.find_name(name, version_requirements)
301
+ end
302
+
303
+ if !installed.empty? && Autobuild.do_update
304
+ # Look if we can update the package ...
305
+ dep = Gem::Dependency.new(name, version_requirements)
306
+ available = gem_fetcher.find_matching(dep, true, true, GemManager.with_prerelease)
307
+ installed_version = installed.map(&:version).max
308
+ available_version = available.map { |(name, v), source| v }.max
309
+ if !available_version
310
+ if version
311
+ raise ConfigError.new, "cannot find any gem with the name '#{name}' and version #{version}"
312
+ else
313
+ raise ConfigError.new, "cannot find any gem with the name '#{name}'"
314
+ end
315
+ end
316
+ needs_update = (available_version > installed_version)
317
+ !needs_update
318
+ else
319
+ !installed.empty?
320
+ end
321
+ end
322
+ gems
323
+ end
324
+
325
+ def parse_package_entry(entry)
326
+ if entry =~ /^([^><=~]*)([><=~]+.*)$/
327
+ [$1.strip, $2.strip]
328
+ else
329
+ [entry]
330
+ end
331
+ end
332
+
333
+ def gems_interaction(gems, cmdlines)
334
+ if OSDependencies.force_osdeps
335
+ return true
336
+ elsif enabled?
337
+ return true
338
+ elsif silent?
339
+ return false
340
+ end
341
+
342
+ # We're not supposed to install rubygem packages but silent is not
343
+ # set, so display information about them anyway
344
+ puts <<-EOMSG
345
+ #{Autoproj.color("The build process and/or the packages require some Ruby Gems to be installed", :bold)}
346
+ #{Autoproj.color("and you required autoproj to not do it itself", :bold)}
347
+ You can use the --all or --ruby options to autoproj osdeps to install these
348
+ packages anyway, and/or change to the osdeps handling mode by running an
349
+ autoproj operation with the --reconfigure option as for instance
350
+ autoproj build --reconfigure
351
+
352
+ The following command line can be used to install them manually
353
+
354
+ #{cmdlines.map { |c| c.join(" ") }.join("\n ")}
355
+
356
+ Autoproj expects these Gems to be installed in #{Autoproj.gem_home} This can
357
+ be overridden by setting the AUTOPROJ_GEM_HOME environment variable manually
358
+
359
+ EOMSG
360
+ print " #{Autoproj.color("Press ENTER to continue ", :bold)}"
361
+
362
+ STDOUT.flush
363
+ STDIN.readline
364
+ puts
365
+ false
366
+ end
367
+ end
368
+ end
369
+
370
+ # Manager for packages provided by external package managers
3
371
  class OSDependencies
4
372
  class << self
5
373
  # When requested to load a file called X.Y, the osdeps code will
@@ -41,11 +409,8 @@ module Autoproj
41
409
  class << self
42
410
  attr_reader :aliases
43
411
  attr_accessor :force_osdeps
44
- attr_accessor :gem_with_prerelease
45
- attr_accessor :gem_doc
46
412
  end
47
413
  @aliases = Hash.new
48
- @gem_doc = false
49
414
 
50
415
  attr_writer :silent
51
416
  def silent?; @silent end
@@ -75,6 +440,11 @@ module Autoproj
75
440
  OSDependencies.load(file)
76
441
  end
77
442
 
443
+ PACKAGE_HANDLERS = [PackageManagers::AptDpkgManager, PackageManagers::GemManager]
444
+ OS_PACKAGE_HANDLERS = {
445
+ 'debian' => 'apt-dpkg'
446
+ }
447
+
78
448
  # The information contained in the OSdeps files, as a hash
79
449
  attr_reader :definitions
80
450
  # All the information contained in all the OSdeps files, as a mapping
@@ -85,22 +455,47 @@ module Autoproj
85
455
  # package name to the osdeps file' full path
86
456
  attr_reader :sources
87
457
 
88
- # The Gem::SpecFetcher object that should be used to query RubyGems, and
89
- # install RubyGems packages
90
- def gem_fetcher
91
- if !@gem_fetcher
92
- Autoproj.message "looking for RubyGems updates"
93
- @gem_fetcher = Gem::SpecFetcher.fetcher
458
+ # Use to override the autodetected OS-specific package handler
459
+ attr_writer :os_package_handler
460
+
461
+ # Returns the package manager object for the current OS
462
+ def os_package_handler
463
+ if @os_package_handler.nil?
464
+ os_names, _ = OSDependencies.operating_system
465
+ if os_names && (key = os_names.find { |name| OS_PACKAGE_HANDLERS[name] })
466
+ @os_package_handler = package_handlers[OS_PACKAGE_HANDLERS[key]]
467
+ if !@os_package_handler
468
+ raise ArgumentError, "found #{OS_PACKAGE_HANDLERS[name]} as the required package handler for #{os_names.join(", ")}, but it is not registered"
469
+ end
470
+ else
471
+ @os_package_handler = PackageManagers::UnknownOSManager.new
472
+ end
473
+ end
474
+ return @os_package_handler
475
+ end
476
+
477
+ # Returns the set of package managers
478
+ def package_handlers
479
+ if !@package_handlers
480
+ @package_handlers = Hash.new
481
+ PACKAGE_HANDLERS.each do |klass|
482
+ obj = klass.new
483
+ obj.names.each do |n|
484
+ @package_handlers[n] = obj
485
+ end
486
+ end
94
487
  end
95
- @gem_fetcher
488
+ @package_handlers
96
489
  end
97
490
 
491
+ # The Gem::SpecFetcher object that should be used to query RubyGems, and
492
+ # install RubyGems packages
98
493
  def initialize(defs = Hash.new, file = nil)
99
494
  @definitions = defs.to_hash
100
495
  @all_definitions = Hash.new { |h, k| h[k] = Array.new }
101
496
 
102
497
  @sources = Hash.new
103
- @installed_packages = Array.new
498
+ @installed_packages = Set.new
104
499
  if file
105
500
  defs.each_key do |package_name|
106
501
  sources[package_name] = file
@@ -169,12 +564,19 @@ module Autoproj
169
564
  @supported_operating_system =
170
565
  if !os_names then false
171
566
  else
172
- os_names.any? { |os_name| OS_AUTO_PACKAGE_INSTALL.has_key?(os_name) }
567
+ os_names.any? { |os_name| OS_PACKAGE_HANDLERS.has_key?(os_name) }
173
568
  end
174
569
  end
175
570
  return @supported_operating_system
176
571
  end
177
572
 
573
+ # Used mainly during testing to bypass the operating system
574
+ # autodetection
575
+ def self.operating_system=(values)
576
+ @supported_operating_system = nil
577
+ @operating_system = values
578
+ end
579
+
178
580
  # Autodetects the operating system name and version
179
581
  #
180
582
  # +osname+ is the operating system name, all in lowercase (e.g. ubuntu,
@@ -280,392 +682,303 @@ module Autoproj
280
682
  return [distributor, [codename, version]]
281
683
  end
282
684
 
283
- # On a dpkg-enabled system, checks if the provided package is installed
284
- # and returns true if it is the case
285
- def self.dpkg_package_installed?(package_name)
286
- if !@dpkg_installed_packages
287
- @dpkg_installed_packages = Set.new
288
- dpkg_status = File.readlines('/var/lib/dpkg/status')
289
-
290
- current_packages = []
291
- is_installed = false
292
- dpkg_status.each do |line|
293
- line = line.chomp
294
- if line == ""
295
- if is_installed
296
- current_packages.each do |pkg|
297
- @dpkg_installed_packages << pkg
298
- end
299
- current_packages.clear
300
- is_installed = false
301
- end
302
- elsif line =~ /Package: (.*)$/
303
- current_packages << $1
304
- elsif line =~ /Provides: (.*)$/
305
- current_packages.concat($1.split(',').map(&:strip))
306
- elsif line == "Status: install ok installed"
307
- is_installed = true
308
- end
309
- end
310
- end
311
-
312
- if package_name =~ /^(\w[a-z0-9+-.]+)/
313
- @dpkg_installed_packages.include?($1)
314
- else
315
- Autoproj.warn "#{package_name} is not a valid Debian package name"
316
- false
685
+ # Return the list of packages that should be installed for +name+
686
+ #
687
+ # The following two simple return values are possible:
688
+ #
689
+ # nil:: +name+ has no definition
690
+ # []:: +name+ has no definition on this OS and/or for this specific OS
691
+ # version
692
+ #
693
+ # In all other cases, the method returns an array of triples:
694
+ #
695
+ # [package_handler, status, package_list]
696
+ #
697
+ # where status is FOUND_PACKAGES if +package_list+ is the list of
698
+ # packages that should be installed with +package_handler+ for +name+,
699
+ # and FOUND_NONEXISTENT if the nonexistent keyword is used for this OS
700
+ # name and version. The package list might be empty even if status ==
701
+ # FOUND_PACKAGES, for instance if the ignore keyword is used.
702
+ def resolve_package(name)
703
+ os_names, os_versions = OSDependencies.operating_system
704
+
705
+ dep_def = definitions[name]
706
+ if !dep_def
707
+ return nil
317
708
  end
318
- end
319
709
 
320
- GAIN_ROOT_ACCESS = <<-EOSCRIPT
321
- # Gain root access using sudo
322
- if test `id -u` != "0"; then
323
- exec sudo /bin/bash $0 "$@"
710
+ # Partition the found definition in all entries that are interesting
711
+ # for us: toplevel os-independent package managers, os-dependent
712
+ # package managers and os-independent package managers selected by
713
+ # OS or version
714
+ if !os_names
715
+ os_names = ['default']
716
+ os_versions = ['default']
717
+ end
324
718
 
325
- fi
326
- EOSCRIPT
719
+ package_handler_names = package_handlers.keys
327
720
 
328
- OS_PACKAGE_CHECK = {
329
- 'debian' => method(:dpkg_package_installed?),
330
- 'ubuntu' => method(:dpkg_package_installed?)
331
- }
332
- OS_USER_PACKAGE_INSTALL = {
333
- 'debian' => "apt-get install '%s'",
334
- 'ubuntu' => "apt-get install '%s'",
335
- 'gentoo' => "emerge '%s'",
336
- 'arch' => "pacman '%s'"
337
- }
721
+ result = []
722
+ found, pkg = partition_osdep_entry(name, dep_def, nil, (package_handler_names - os_package_handler.names), os_names, os_versions)
723
+ if found
724
+ result << [os_package_handler, found, pkg]
725
+ end
338
726
 
339
- OS_AUTO_PACKAGE_INSTALL = {
340
- 'debian' => "export DEBIAN_FRONTEND=noninteractive; apt-get install -y '%s'",
341
- 'ubuntu' => "export DEBIAN_FRONTEND=noninteractive; apt-get install -y '%s'",
342
- 'gentoo' => "emerge --noreplace '%s'",
343
- 'arch' => "pacman -Sy --noconfirm '%s'"
344
- }
727
+ # NOTE: package_handlers might contain the same handler multiple
728
+ # times (when a package manager has multiple names). That's why we
729
+ # do a to_set.each
730
+ package_handlers.each_value.to_set.each do |handler|
731
+ found, pkg = partition_osdep_entry(name, dep_def, handler.names, [], os_names, os_versions)
732
+ if found
733
+ result << [handler, found, pkg]
734
+ end
735
+ end
345
736
 
346
- NO_PACKAGE = 0
347
- WRONG_OS = 1
348
- WRONG_OS_VERSION = 2
349
- IGNORE = 3
350
- PACKAGES = 4
351
- UNKNOWN_OS = 7
352
- AVAILABLE = 10
737
+ result.map do |handler, status, entries|
738
+ if handler.respond_to?(:parse_package_entry)
739
+ [handler, status, entries.map { |s| handler.parse_package_entry(s) }]
740
+ else
741
+ [handler, status, entries]
742
+ end
743
+ end
744
+ end
353
745
 
354
- # Check for the definition of +name+ for this operating system
746
+ # Value returned by #resolve_package and #partition_osdep_entry in
747
+ # the status field. See the documentation of these methods for more
748
+ # information
749
+ FOUND_PACKAGES = 0
750
+ # Value returned by #resolve_package and #partition_osdep_entry in
751
+ # the status field. See the documentation of these methods for more
752
+ # information
753
+ FOUND_NONEXISTENT = 1
754
+
755
+ # Helper method that parses the osdep definition to split between the
756
+ # parts needed for this OS and specific package handlers.
355
757
  #
356
- # It can return
758
+ # +osdep_name+ is the name of the osdep. It is used to resolve explicit
759
+ # mentions of a package handler, i.e. so that:
357
760
  #
358
- # NO_PACKAGE::
359
- # there are no package definition for +name
360
- # UNKNOWN_OS::
361
- # this is not an OS autoproj knows how to deal with
362
- # WRONG_OS::
363
- # there are a package definition, but not for this OS
364
- # WRONG_OS_VERSION::
365
- # there is a package definition for this OS, but not for this
366
- # particular version of the OS
367
- # IGNORE::
368
- # there is a package definition that told us to ignore the package
369
- # [PACKAGES, definition]::
370
- # +definition+ is an array of package names that this OS's package
371
- # manager can understand
372
- def resolve_package(name)
373
- os_names, os_versions = OSDependencies.operating_system
761
+ # pkg: gem
762
+ #
763
+ # is resolved as the 'pkg' package to be installed by the 'gem' handler
764
+ #
765
+ # +dep_def+ is the content to parse. It can be a string, array or hash
766
+ #
767
+ # +handler_names+ is a list of entries that we are looking for. If it is
768
+ # not nil, only entries that explicitely refer to +handler_names+ will
769
+ # be browsed, i.e. in:
770
+ #
771
+ # pkg:
772
+ # - test: 1
773
+ # - [a, list, of, packages]
774
+ #
775
+ # partition_osdep_entry('osdep_name', data, ['test'], [])
776
+ #
777
+ # will ignore the toplevel list of packages, while
778
+ #
779
+ # partition_osdep_entry('osdep_name', data, nil, [])
780
+ #
781
+ # will return it.
782
+ #
783
+ # +excluded+ is a list of branches that should be ignored during
784
+ # parsing. It is used to e.g. ignore 'gem' when browsing for the main OS
785
+ # package list. For instance, in
786
+ #
787
+ # pkg:
788
+ # - test
789
+ # - [a, list, of, packages]
790
+ #
791
+ # partition_osdep_entry('osdep_name', data, nil, ['test'])
792
+ #
793
+ # the returned value will only include the list of packages (and not
794
+ # 'test')
795
+ #
796
+ # The rest of the arguments are array of strings that contain list of
797
+ # keys to browse for (usually, the OS names and version)
798
+ #
799
+ # The return value is either nil if no packages were found, or a pair
800
+ # [status, package_list] where status is FOUND_NONEXISTENT if the
801
+ # nonexistent keyword was found, and FOUND_PACKAGES if either packages
802
+ # or the ignore keyword were found.
803
+ #
804
+ def partition_osdep_entry(osdep_name, dep_def, handler_names, excluded, *keys)
805
+ keys, *additional_keys = *keys
806
+ found = false
807
+ nonexistent = false
808
+ result = []
809
+ found_keys = []
810
+ Array(dep_def).each do |names, values|
811
+ if !values
812
+ # Raw array of packages. Possible only if we are not at toplevel
813
+ # (i.e. if we already have a handler)
814
+ if names == 'ignore'
815
+ found = true if !handler_names
816
+ elsif names == 'nonexistent'
817
+ nonexistent = true if !handler_names
818
+ elsif !handler_names && names.kind_of?(Array)
819
+ result.concat(result)
820
+ found = true
821
+ elsif names.respond_to?(:to_str)
822
+ if excluded.include?(names)
823
+ elsif handler_names && handler_names.include?(names)
824
+ result << osdep_name
825
+ found = true
826
+ elsif !handler_names
827
+ result << names
828
+ found = true
829
+ end
830
+ elsif names.respond_to?(:to_hash)
831
+ rec_found, rec_result = partition_osdep_entry(osdep_name, names, handler_names, excluded, keys, *additional_keys)
832
+ if rec_found == FOUND_NONEXISTENT then nonexistent = true
833
+ elsif rec_found == FOUND_PACKAGES then found = true
834
+ end
835
+ result.concat(rec_result)
836
+ end
837
+ elsif keys
838
+ if names.respond_to?(:to_str) # names could be an array already
839
+ names = names.split(',')
840
+ end
374
841
 
375
- dep_def = definitions[name]
376
- if !dep_def
377
- return NO_PACKAGE
378
- elsif dep_def == 'ignore'
379
- return IGNORE
380
- elsif dep_def == 'nonexistent'
381
- return WRONG_OS_VERSION
382
- elsif !os_names
383
- return UNKNOWN_OS
384
- end
385
-
386
- # Find a matching entry for the OS name
387
- os_entry = nil
388
- os_names.find do |os_name|
389
- os_entry = dep_def.find do |name_list, _|
390
- name_list.split(',').
391
- map(&:downcase).
392
- any? { |n| n == os_name }
393
- end
394
- end
395
-
396
- if !os_entry
397
- return WRONG_OS
398
- end
399
- data = os_entry.last
400
-
401
- # This package does not need to be installed on this operating system (example: build tools on Gentoo)
402
- if !data || data == "ignore"
403
- return IGNORE
404
- end
405
-
406
- # If data is a hash, it means we have to check the OS version as well
407
- if data.kind_of?(Hash)
408
- # Look in +data+ for specific version. We look, in order, in the
409
- # os_versions field (detected OS versions), and return the first
410
- # matching entry
411
- version_entry = nil
412
- # First, look for an exact match
413
- found = os_versions.find do |os_ver|
414
- version_entry = data.find do |version_list, _|
415
- version_list.to_s.split(',').
416
- map(&:downcase).
417
- any? { |v| v == os_ver }
842
+ if handler_names
843
+ if matching_name = handler_names.find { |k| names.any? { |name_tag| k == name_tag.downcase } }
844
+ rec_found, rec_result = partition_osdep_entry(osdep_name, values, nil, excluded, keys, *additional_keys)
845
+ if rec_found == FOUND_NONEXISTENT then nonexistent = true
846
+ elsif rec_found == FOUND_PACKAGES then found = true
847
+ end
848
+ result.concat(rec_result)
849
+ end
418
850
  end
419
- end
420
- if !found
421
- # Then relax the matching ...
422
- found = os_versions.find do |os_ver|
423
- version_entry = data.find do |version_list, _|
424
- version_list.to_s.split(',').
425
- map(&:downcase).
426
- any? { |v| Regexp.new(v) =~ os_ver }
851
+
852
+ matching_name = keys.find { |k| names.any? { |name_tag| k == name_tag.downcase } }
853
+ if matching_name
854
+ rec_found, rec_result = partition_osdep_entry(osdep_name, values, handler_names, excluded, *additional_keys)
855
+
856
+ if rec_found
857
+ idx = keys.index(matching_name)
858
+ found_keys[idx] ||= [0, []]
859
+ found_keys[idx][0] += rec_found
860
+ found_keys[idx][1].concat(rec_result)
427
861
  end
428
862
  end
429
863
  end
430
- if Autoproj.verbose
431
- Autoproj.message "selected OS version #{found} for osdep #{name}: #{version_entry.inspect}"
432
- end
433
-
434
- if !version_entry
435
- return WRONG_OS_VERSION
864
+ end
865
+ if found_keys = found_keys.compact.first
866
+ if found_keys[0] > 0
867
+ nonexistent = true
868
+ else
869
+ found = true
436
870
  end
437
- data = version_entry.last
871
+ result.concat(found_keys[1])
438
872
  end
439
873
 
440
- if data.respond_to?(:to_str) && data.to_str == 'nonexistent'
441
- return WRONG_OS_VERSION
442
- end
874
+ found =
875
+ if nonexistent then FOUND_NONEXISTENT
876
+ elsif found then FOUND_PACKAGES
877
+ else false
878
+ end
443
879
 
444
- if data.respond_to?(:to_ary)
445
- # List of packages
446
- return [PACKAGES, data]
447
- elsif data.respond_to?(:to_str)
448
- # Single package
449
- return [PACKAGES, [data.to_str]]
450
- else
451
- raise ConfigError.new, "invalid package specification #{data} in #{source_of(name)}"
452
- end
880
+ return found, result
453
881
  end
454
882
 
455
883
  # Resolves the given OS dependencies into the actual packages that need
456
884
  # to be installed on this particular OS.
457
885
  #
458
- # Raises ConfigError if some packages can't be found
886
+ # Raises ConfigError if some packages can't be found or if the
887
+ # nonexistent keyword was found for some of them
459
888
  def resolve_os_dependencies(dependencies)
460
- os_names, _ = OSDependencies.operating_system
461
-
462
- os_packages = []
889
+ all_packages = []
463
890
  dependencies.each do |name|
464
891
  result = resolve_package(name)
465
- if result == NO_PACKAGE
892
+ if !result
466
893
  raise ConfigError.new, "there is no osdeps definition for #{name}"
467
- elsif result == WRONG_OS
468
- raise ConfigError.new, "there is an osdeps definition for #{name}, but not for this operating system"
469
- elsif result == WRONG_OS_VERSION
470
- raise ConfigError.new, "there is an osdeps definition for #{name}, but not for this particular operating system version"
471
- elsif result == IGNORE
472
- next
473
- elsif result[0] == PACKAGES
474
- os_packages.concat(result[1])
894
+ elsif result.empty?
895
+ os_names, os_versions = OSDependencies.operating_system
896
+ raise ConfigError.new, "there is an osdeps definition for #{name}, but not for this operating system and version (resp. #{os_names.join(", ")} and #{os_versions.join(", ")})"
897
+ else
898
+ result.each do |handler, status, packages|
899
+ if status == FOUND_NONEXISTENT
900
+ raise ConfigError.new, "there is an osdep definition for #{name}, and it explicitely states that this package does not exist on your OS"
901
+ end
902
+ if entry = all_packages.find { |h, _| h == handler }
903
+ entry[1].concat(packages)
904
+ else
905
+ all_packages << [handler, packages]
906
+ end
907
+ end
475
908
  end
476
909
  end
477
910
 
478
- if !os_names.any? { |os_name| OS_AUTO_PACKAGE_INSTALL.has_key?(os_name) }
479
- raise ConfigError.new, "I don't know how to install packages on #{os_names.first}"
911
+ all_packages.delete_if do |handler, pkg|
912
+ pkg.empty?
480
913
  end
481
-
482
- return os_packages
914
+ return all_packages
483
915
  end
484
916
 
485
917
 
486
- def generate_user_os_script(os_names, os_packages)
487
- user_package_install = nil
488
- os_names.find do |os_name|
489
- user_package_install = OS_USER_PACKAGE_INSTALL[os_name]
490
- end
491
- if user_package_install
492
- (user_package_install % [os_packages.join("' '")])
493
- else generate_auto_os_script(os_names, os_packages)
494
- end
495
- end
496
- def generate_auto_os_script(os_names, os_packages)
497
- auto_package_install = nil
498
- os_names.find do |os_name|
499
- auto_package_install = OS_AUTO_PACKAGE_INSTALL[os_name]
500
- end
501
- (auto_package_install % [os_packages.join("' '")])
502
- end
503
-
504
918
  # Returns true if +name+ is an acceptable OS package for this OS and
505
919
  # version
506
920
  def has?(name)
507
- availability_of(name) == AVAILABLE
921
+ status = availability_of(name)
922
+ status == AVAILABLE || status == IGNORE
508
923
  end
509
924
 
925
+ # Value returned by #availability_of if the required package has no
926
+ # definition
927
+ NO_PACKAGE = 0
928
+ # Value returned by #availability_of if the required package has
929
+ # definitions, but not for this OS name or version
930
+ WRONG_OS = 1
931
+ # Value returned by #availability_of if the required package has
932
+ # definitions, but the local OS is unknown
933
+ UNKNOWN_OS = 2
934
+ # Value returned by #availability_of if the required package has
935
+ # definitions, but the nonexistent keyword was used for this OS
936
+ NONEXISTENT = 3
937
+ # Value returned by #availability_of if the required package is
938
+ # available
939
+ AVAILABLE = 4
940
+ # Value returned by #availability_of if the required package is
941
+ # available, but no package needs to be installed to have it
942
+ IGNORE = 5
943
+
510
944
  # If +name+ is an osdeps that is available for this operating system,
511
- # returns AVAILABLE. Otherwise, returns the same error code than
512
- # resolve_package.
945
+ # returns AVAILABLE. Otherwise, returns one of:
946
+ #
947
+ # NO_PACKAGE:: the package has no definitions
948
+ # WRONG_OS:: the package has a definition, but not for this OS
949
+ # UNKNOWN_OS:: the package has a definition, but the local OS is unknown
950
+ # NONEXISTENT:: the package has a definition, but the 'nonexistent'
951
+ # keyword was found for this OS
952
+ # AVAILABLE:: the package is available for this OS
953
+ # IGNORE:: the package is available for this OS, but no packages need to
954
+ # be installed for it
513
955
  def availability_of(name)
514
- osdeps, gemdeps = partition_packages([name].to_set)
515
- if !osdeps.empty?
516
- osdeps.each do |dep_name|
517
- status = resolve_package(dep_name)
518
- if !status.respond_to?(:to_ary) && status != IGNORE
519
- return status
520
- end
521
- end
522
- AVAILABLE
523
- elsif !gemdeps.empty?
524
- AVAILABLE
525
- else
526
- NO_PACKAGE
956
+ resolved = resolve_package(name)
957
+ if !resolved
958
+ return NO_PACKAGE
527
959
  end
528
- end
529
960
 
530
- # call-seq:
531
- # partition_packages(package_names) => os_packages, gem_packages
532
- #
533
- # Resolves the package names listed in +package_set+, and returns a set
534
- # of packages that have to be installed using the platform's native
535
- # package manager, and the set of packages that have to be installed
536
- # using Ruby's package manager, RubyGems.
537
- #
538
- # The os_packages arrays is a list of names (strings)
539
- #
540
- # The gem_packages arrays is a list of [name, version] pairs. +version+
541
- # is a version string, that is set only if the package has been given
542
- # with a =VERSION specification, e.g.
543
- #
544
- # gems:
545
- # hoe=1.8.0
546
- #
547
- # Raises ConfigError if an error exists in the osdeps files, and returns
548
- # empty sets if the package can't be found
549
- def partition_packages(package_set)
550
- package_set = package_set.
551
- map { |name| OSDependencies.aliases[name] || name }.
552
- to_set
553
-
554
- osdeps, gems = [], []
555
- package_set.to_set.each do |name|
556
- pkg_def = definitions[name]
557
- if !pkg_def
558
- # Error cases are taken care of later, because that is were
559
- # the automatic/manual osdeps logic lies
560
- osdeps << name
561
- next
562
- end
563
-
564
- pkg_def = pkg_def.dup
565
-
566
- if pkg_def.respond_to?(:to_str)
567
- case(pkg_def.to_str)
568
- when "ignore" then
569
- osdeps << name
570
- when "gem" then
571
- gems << name
572
- else
573
- # This is *not* handled later, as is the absence of a
574
- # package definition. The reason is that it is a bad
575
- # configuration file, and should be fixed by the user
576
- raise ConfigError.new, "unknown OS-independent package management type #{pkg_def} for #{name}"
577
- end
961
+ if resolved.empty?
962
+ if !OSDependencies.operating_system
963
+ return UNKNOWN_OS
578
964
  else
579
- pkg_def.delete_if do |distrib_name, defs|
580
- if distrib_name == "gem"
581
- gems.concat([*defs])
582
- true
583
- end
584
- end
585
- if !pkg_def.empty?
586
- osdeps << name
587
- end
965
+ return WRONG_OS
588
966
  end
589
967
  end
590
- gems.map! do |name|
591
- if name =~ /^([^><=~]*)([><=~]+.*)$/
592
- [$1.strip, $2.strip]
593
- else
594
- [name]
595
- end
596
- end
597
- return osdeps, gems
598
- end
599
968
 
600
- def guess_gem_program
601
- if Autobuild.programs['gem']
602
- return Autobuild.programs['gem']
603
- end
604
-
605
- ruby_bin = Config::CONFIG['RUBY_INSTALL_NAME']
606
- if ruby_bin =~ /^ruby(.+)$/
607
- Autobuild.programs['gem'] = "gem#{$1}"
608
- else
609
- Autobuild.programs['gem'] = "gem"
969
+ resolved = resolved.delete_if { |_, status, list| status == FOUND_PACKAGES && list.empty? }
970
+ failed = resolved.find_all do |handler, status, list|
971
+ status == FOUND_NONEXISTENT
610
972
  end
611
- end
612
-
613
- # Returns true if the osdeps system knows how to remove uptodate
614
- # packages from the needs-to-be-installed package list on this OS
615
- def can_filter_uptodate_packages?
616
- os_names, _ = OSDependencies.operating_system
617
- !!os_names.any? { |os_name| OS_PACKAGE_CHECK[os_name] }
618
- end
619
-
620
- # Returns the set of packages in +packages+ that are not already
621
- # installed on this OS, if it is supported
622
- def filter_uptodate_os_packages(packages, os_names)
623
- check_method = nil
624
- os_names.find do |os_name|
625
- check_method = OS_PACKAGE_CHECK[os_name]
626
- end
627
- return packages.dup if !check_method
628
-
629
- packages.find_all { |pkg| !check_method[pkg] }
630
- end
631
-
632
- # Returns the set of RubyGem packages in +packages+ that are not already
633
- # installed, or that can be upgraded
634
- def filter_uptodate_gems(gems)
635
- # Don't install gems that are already there ...
636
- gems = gems.dup
637
- gems.delete_if do |name, version|
638
- version_requirements = Gem::Requirement.new(version || '>= 0')
639
- installed =
640
- if Gem::Specification.respond_to?(:find_by_name)
641
- begin
642
- [Gem::Specification.find_by_name(name, version_requirements)]
643
- rescue Gem::LoadError
644
- []
645
- end
646
- else
647
- Gem.source_index.find_name(name, version_requirements)
648
- end
649
- if !installed.empty? && Autobuild.do_update
650
- # Look if we can update the package ...
651
- dep = Gem::Dependency.new(name, version_requirements)
652
- available = gem_fetcher.find_matching(dep, true, true, OSDependencies.gem_with_prerelease)
653
- installed_version = installed.map(&:version).max
654
- available_version = available.map { |(name, v), source| v }.max
655
- if !available_version
656
- if version
657
- raise ConfigError.new, "cannot find any gem with the name '#{name}' and version #{version}"
658
- else
659
- raise ConfigError.new, "cannot find any gem with the name '#{name}'"
660
- end
661
- end
662
- needs_update = (available_version > installed_version)
663
- !needs_update
973
+ if failed.empty?
974
+ if resolved.empty?
975
+ return IGNORE
664
976
  else
665
- !installed.empty?
977
+ return AVAILABLE
666
978
  end
979
+ else
980
+ return NONEXISTENT
667
981
  end
668
- gems
669
982
  end
670
983
 
671
984
  HANDLE_ALL = 'all'
@@ -774,7 +1087,15 @@ So, what do you want ? (all, ruby, os or none)
774
1087
  # If set to true (the default), #install will try to remove the list of
775
1088
  # already uptodate packages from the installed packages. Set to false to
776
1089
  # install all packages regardless of their status
777
- attr_accessor :filter_uptodate_packages
1090
+ attr_writer :filter_uptodate_packages
1091
+
1092
+ # If set to true (the default), #install will try to remove the list of
1093
+ # already uptodate packages from the installed packages. Use
1094
+ # #filter_uptodate_packages= to set it to false to install all packages
1095
+ # regardless of their status
1096
+ def filter_uptodate_packages?
1097
+ !!@filter_uptodate_packages
1098
+ end
778
1099
 
779
1100
  # Override the osdeps mode
780
1101
  def osdeps_mode=(value)
@@ -828,21 +1149,6 @@ So, what do you want ? (all, ruby, os or none)
828
1149
  # The set of packages that have already been installed
829
1150
  attr_reader :installed_packages
830
1151
 
831
- def osdeps_interaction_unknown_os(osdeps)
832
- puts <<-EOMSG
833
- #{Autoproj.color("The build process requires some other software packages to be installed on our operating system", :bold)}
834
- #{Autoproj.color("If they are already installed, simply ignore this message", :red)}
835
-
836
- #{osdeps.join("\n ")}
837
-
838
- EOMSG
839
- print Autoproj.color("Press ENTER to continue", :bold)
840
- STDOUT.flush
841
- STDIN.readline
842
- puts
843
- nil
844
- end
845
-
846
1152
  def installs_os_packages?
847
1153
  osdeps_mode == HANDLE_ALL || osdeps_mode == HANDLE_OS
848
1154
  end
@@ -851,170 +1157,36 @@ So, what do you want ? (all, ruby, os or none)
851
1157
  osdeps_mode == HANDLE_ALL || osdeps_mode == HANDLE_RUBY
852
1158
  end
853
1159
 
854
- def osdeps_interaction(osdeps, os_packages, shell_script, silent)
855
- if !OSDependencies.supported_operating_system?
856
- if silent
857
- return false
858
- else
859
- return osdeps_interaction_unknown_os(osdeps)
860
- end
861
- elsif OSDependencies.force_osdeps
862
- return true
863
- elsif osdeps_mode == HANDLE_ALL || osdeps_mode == HANDLE_OS
864
- return true
865
- elsif silent
866
- return false
867
- end
868
-
869
- # We're asked to not install the OS packages but to display them
870
- # anyway, do so now
871
- puts <<-EOMSG
872
-
873
- #{Autoproj.color("The build process and/or the packages require some other software to be installed", :bold)}
874
- #{Autoproj.color("and you required autoproj to not install them itself", :bold)}
875
- #{Autoproj.color("\nIf these packages are already installed, simply ignore this message\n", :red) if !can_filter_uptodate_packages?}
876
- The following packages are available as OS dependencies, i.e. as prebuilt
877
- packages provided by your distribution / operating system. You will have to
878
- install them manually if they are not already installed
879
-
880
- #{os_packages.sort.join("\n ")}
881
-
882
- the following command line(s) can be run as root to install them:
883
-
884
- #{shell_script.split("\n").join("\n| ")}
885
-
886
- EOMSG
887
- print " #{Autoproj.color("Press ENTER to continue ", :bold)}"
888
- STDOUT.flush
889
- STDIN.readline
890
- puts
891
- false
892
- end
893
-
894
- def gems_interaction(gems, cmdlines, silent)
895
- if OSDependencies.force_osdeps
896
- return true
897
- elsif osdeps_mode == HANDLE_ALL || osdeps_mode == HANDLE_RUBY
898
- return true
899
- elsif silent
900
- return false
901
- end
902
-
903
- # We're not supposed to install rubygem packages but silent is not
904
- # set, so display information about them anyway
905
- puts <<-EOMSG
906
- #{Autoproj.color("The build process and/or the packages require some Ruby Gems to be installed", :bold)}
907
- #{Autoproj.color("and you required autoproj to not do it itself", :bold)}
908
- You can use the --all or --ruby options to autoproj osdeps to install these
909
- packages anyway, and/or change to the osdeps handling mode by running an
910
- autoproj operation with the --reconfigure option as for instance
911
- autoproj build --reconfigure
912
-
913
- The following command line can be used to install them manually
914
-
915
- #{cmdlines.map { |c| c.join(" ") }.join("\n ")}
916
-
917
- Autoproj expects these Gems to be installed in #{Autoproj.gem_home} This can
918
- be overridden by setting the AUTOPROJ_GEM_HOME environment variable manually
919
-
920
- EOMSG
921
- print " #{Autoproj.color("Press ENTER to continue ", :bold)}"
922
-
923
- STDOUT.flush
924
- STDIN.readline
925
- puts
926
- false
927
- end
928
1160
 
929
1161
  # Requests the installation of the given set of packages
930
1162
  def install(packages, package_osdeps = Hash.new)
931
- handled_os = OSDependencies.supported_operating_system?
932
- # Remove the set of packages that have already been installed
933
- packages -= installed_packages
934
- return if packages.empty?
935
-
936
- osdeps, gems = partition_packages(packages)
937
- if handled_os
938
- os_names, _ = OSDependencies.operating_system
939
- os_packages = resolve_os_dependencies(osdeps)
940
- if filter_uptodate_packages
941
- os_packages = filter_uptodate_os_packages(os_packages, os_names)
942
- end
943
- end
944
- if filter_uptodate_packages
945
- gems = filter_uptodate_gems(gems)
1163
+ os_package_handler.enabled = installs_os_packages?
1164
+ package_handlers['gem'].enabled = installs_ruby_packages?
1165
+ package_handlers.each_value do |v|
1166
+ v.silent = self.silent?
946
1167
  end
947
1168
 
948
- did_something = false
949
-
950
- if !osdeps.empty? && (!os_packages || !os_packages.empty?)
951
- if handled_os
952
- shell_script = generate_auto_os_script(os_names, os_packages)
953
- user_shell_script = generate_user_os_script(os_names, os_packages)
954
- end
955
- if osdeps_interaction(osdeps, os_packages, user_shell_script, silent?)
956
- Autoproj.message " installing OS packages: #{os_packages.sort.join(", ")}"
957
-
958
- if Autoproj.verbose
959
- Autoproj.message "Generating installation script for non-ruby OS dependencies"
960
- Autoproj.message shell_script
961
- end
962
-
963
- File.open('/tmp/autoproj_osdeps_lock', 'w') do |lock_io|
964
- begin
965
- while !lock_io.flock(File::LOCK_EX | File::LOCK_NB)
966
- Autoproj.message " waiting for other autoproj instances to finish their osdeps installation"
967
- sleep 5
968
- end
969
-
970
- Tempfile.open('osdeps_sh') do |io|
971
- io.puts "#! /bin/bash"
972
- io.puts GAIN_ROOT_ACCESS
973
- io.write shell_script
974
- io.flush
975
- Autobuild::Subprocess.run 'autoproj', 'osdeps', '/bin/bash', io.path
976
- end
977
- ensure
978
- lock_io.flock(File::LOCK_UN)
979
- end
980
- end
981
- did_something = true
982
- end
983
- end
984
-
985
- # Now install the RubyGems
986
- if !gems.empty?
987
- guess_gem_program
1169
+ # Remove the set of packages that have already been installed
1170
+ packages = packages.to_set - installed_packages
1171
+ return false if packages.empty?
988
1172
 
989
- base_cmdline = [Autobuild.tool('gem'), 'install']
990
- if !OSDependencies.gem_doc
991
- base_cmdline << '--no-rdoc' << '--no-ri'
1173
+ packages = resolve_os_dependencies(packages)
1174
+ packages = packages.map do |handler, list|
1175
+ if filter_uptodate_packages? && handler.respond_to?(:filter_uptodate_packages)
1176
+ list = handler.filter_uptodate_packages(list)
992
1177
  end
993
1178
 
994
- if Autoproj::OSDependencies.gem_with_prerelease
995
- base_cmdline << "--prerelease"
1179
+ if !list.empty?
1180
+ [handler, list]
996
1181
  end
997
- with_version, without_version = gems.partition { |name, v| v }
1182
+ end.compact
1183
+ return false if packages.empty?
998
1184
 
999
- cmdlines = []
1000
- if !without_version.empty?
1001
- cmdlines << (base_cmdline + without_version.flatten)
1002
- end
1003
- with_version.each do |name, v|
1004
- cmdlines << base_cmdline + [name, "-v", v]
1005
- end
1006
-
1007
- if gems_interaction(gems, cmdlines, silent?)
1008
- Autoproj.message "installing/updating RubyGems dependencies: #{gems.map { |g| g.join(" ") }.sort.join(", ")}"
1009
-
1010
- cmdlines.each do |c|
1011
- Autobuild::Subprocess.run 'autoproj', 'osdeps', *c
1012
- end
1013
- did_something = true
1014
- end
1185
+ packages.each do |handler, list|
1186
+ handler.install(list)
1187
+ @installed_packages |= list.to_set
1015
1188
  end
1016
-
1017
- did_something
1189
+ true
1018
1190
  end
1019
1191
  end
1020
1192
  end