autoproj 1.7.21.b1 → 1.7.21.b2

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