autoproj 1.5.8 → 1.6.0.rc1

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.
@@ -25,7 +25,9 @@ Adding a package
25
25
 
26
26
  Adding a package to a package set involves changing two files:
27
27
 
28
- * the package set's autobuild file that declares what type of package it is and
28
+ * one of the package set's autobuild file that declares what packages there
29
+ are. Any file ending with .autobuild is loaded as an autobuild file by
30
+ autoproj.
29
31
  * the package set's source.yml file that declares where to get it (version
30
32
  control information)
31
33
 
@@ -3,6 +3,29 @@ require 'fileutils'
3
3
  require 'autobuild'
4
4
  require 'set'
5
5
 
6
+ def explicit_osdeps_selection(name)
7
+ if !Autoproj.declared_option?("osdeps_#{name}")
8
+ if Autoproj.has_config_key?("osdeps_#{name}")
9
+ doc_string = "install #{name} from source ?"
10
+ else
11
+ # Declare the option
12
+ doc_string =<<-EOT
13
+ The #{name} package is listed as a dependency of #{self.name}. It is listed as an operating
14
+ system package for other operating systems than yours, and is also listed as a source package.
15
+ Since you requested manual updates, I have to ask you:
16
+
17
+ Do you want me to build #{name} from source ? If you say 'no', you will have to install it yourself.
18
+ EOT
19
+ end
20
+
21
+ Autoproj.configuration_option(
22
+ "osdeps_#{name}", "boolean",
23
+ :default => "yes",
24
+ :doc => doc_string)
25
+ end
26
+ !Autoproj.user_config("osdeps_#{name}")
27
+ end
28
+
6
29
  module Autobuild
7
30
  class Package
8
31
  def autoproj_name # :nodoc:
@@ -11,23 +34,40 @@ module Autobuild
11
34
 
12
35
  alias __depends_on__ depends_on
13
36
  def depends_on(name)
14
- explicit_selection = Autoproj.manifest.explicitly_selected_package?(name)
15
- if Autoproj.osdeps.has?(name) && !explicit_selection
16
- @os_packages ||= Set.new
17
- @os_packages << name
18
- else
19
- begin
20
- __depends_on__(name)
21
- rescue Exception => e
22
- if explicit_selection
23
- raise e
24
- else
25
- # Re-call osdeps to get a proper error message
26
- osdeps, gems = Autoproj.osdeps.partition_packages([name].to_set, name => [self.name])
27
- Autoproj.osdeps.resolve_os_dependencies(osdeps)
37
+ explicit_selection = Autoproj.manifest.explicitly_selected_package?(name)
38
+ osdeps_availability = Autoproj.osdeps.availability_of(name)
39
+ available_as_source = Autobuild::Package[name]
40
+
41
+ # Prefer OS packages to source packages
42
+ if !explicit_selection
43
+ if osdeps_availability == Autoproj::OSDependencies::AVAILABLE
44
+ @os_packages ||= Set.new
45
+ @os_packages << name
46
+ return
47
+ end
48
+
49
+ if osdeps_availability == Autoproj::OSDependencies::UNKNOWN_OS
50
+ # If we can't handle that OS, but other OSes have a
51
+ # definition for it, we assume that it can be installed as
52
+ # an external package. However, if it is also available as a
53
+ # source package, prompt the user
54
+ if !available_as_source || explicit_osdeps_selection(name)
55
+ @os_packages ||= Set.new
56
+ @os_packages << name
57
+ return
28
58
  end
29
59
  end
60
+
61
+ if !available_as_source
62
+ # Call osdeps to get a proper error message
63
+ osdeps, gems = Autoproj.osdeps.partition_packages([name].to_set, name => [self.name])
64
+ Autoproj.osdeps.resolve_os_dependencies(osdeps)
65
+ # Should never reach further than that
66
+ end
30
67
  end
68
+
69
+
70
+ __depends_on__(name) # to get the error message
31
71
  end
32
72
 
33
73
  def depends_on_os_package(name)
@@ -83,12 +123,18 @@ module Autoproj
83
123
  def self.filter_load_exception(error, source, path)
84
124
  raise error if Autoproj.verbose
85
125
  rx_path = Regexp.quote(path)
86
- error_line = error.backtrace.find { |l| l =~ /#{rx_path}/ }
87
- line_number = Integer(/#{rx_path}:(\d+)/.match(error_line)[1])
88
- if source.local?
89
- raise ConfigError, "#{path}:#{line_number}: #{error.message}", error.backtrace
126
+ if error_line = error.backtrace.find { |l| l =~ /#{rx_path}/ }
127
+ if line_number = Integer(/#{rx_path}:(\d+)/.match(error_line)[1])
128
+ line_number = "#{line_number}:"
129
+ end
130
+
131
+ if source.local?
132
+ raise ConfigError, "#{path}:#{line_number} #{error.message}", error.backtrace
133
+ else
134
+ raise ConfigError, "#{File.basename(path)}(source=#{source.name}):#{line_number} #{error.message}", error.backtrace
135
+ end
90
136
  else
91
- raise ConfigError, "#{File.basename(path)}(source=#{source.name}):#{line_number}: #{error.message}", error.backtrace
137
+ raise error
92
138
  end
93
139
  end
94
140
 
@@ -98,6 +144,8 @@ module Autoproj
98
144
  @file_stack.push([source, File.basename(path)])
99
145
  begin
100
146
  Kernel.load path
147
+ rescue ConfigError => e
148
+ raise
101
149
  rescue Exception => e
102
150
  filter_load_exception(e, source, path)
103
151
  end
@@ -20,12 +20,68 @@ module Autoproj
20
20
  end
21
21
  end
22
22
 
23
+ def self.color(*args)
24
+ console.color(*args)
25
+ end
26
+
23
27
  # Displays a warning message
24
28
  def self.warn(message)
25
29
  Autoproj.progress(" WARN: #{message}", :magenta)
26
30
  end
27
31
 
28
32
  module CmdLine
33
+ def self.handle_automatic_osdeps
34
+ if !Autoproj.has_config_key?('automatic_osdeps') && ENV['AUTOPROJ_AUTOMATIC_OSDEPS']
35
+ mode = ENV['AUTOPROJ_AUTOMATIC_OSDEPS']
36
+ mode =
37
+ if mode == 'true' then Autoproj::OSDependencies::AUTOMATIC
38
+ elsif mode == 'false' then Autoproj::OSDependencies::MANUAL
39
+ elsif mode == 'wait' then Autoproj::OSDependencies::WAIT
40
+ else Autoproj::OSDependencies::ASK
41
+ end
42
+
43
+ Autoproj.change_option('automatic_osdeps', mode, true)
44
+ end
45
+
46
+ if Autoproj.has_config_key?("automatic_osdeps")
47
+ doc_string = "Should autoproj handle the OS package installation automatically (yes, no, wait or ask) ?"
48
+ else
49
+ # Ask the user for the automatic_osdeps option
50
+ doc_string =<<-EOT
51
+ #{color("Should autoproj handle the OS package installation automatically (yes, no, wait or ask) ?", :bold)}
52
+ If you say "no", the list of OS dependencies that need to be installed will be listed,
53
+ and autoproj will go on, assuming that you have installed them yourself. If you say
54
+ "ask", you will be prompted each time a package needs to be installed. Finally, if you
55
+ say "wait", autoproj will simply wait for you to press ENTER to continue after it prompted
56
+ you for the dependencies.
57
+
58
+ This value can be changed anytime by calling an autoproj operation with the --reconfigure
59
+ option (e.g. autoproj update --reconfigure). Moreover, the "autoproj osdeps" call will
60
+ always allow you to install OS dependencies through autoproj.
61
+
62
+ EOT
63
+ doc_string = doc_string.strip
64
+ end
65
+
66
+ Autoproj.configuration_option 'automatic_osdeps', 'string',
67
+ :default => 'yes',
68
+ :doc => doc_string do |value|
69
+ begin
70
+ Autoproj::BuildOption.validate_boolean(value, Hash.new)
71
+ rescue Autoproj::InputError
72
+ if value.to_s == "ask"
73
+ :ask
74
+ elsif value.to_s == "wait"
75
+ :wait
76
+ else
77
+ raise Autoproj::InputError, "invalid value. Please answer 'yes', 'no', 'wait' or 'ask' -- without the quotes"
78
+ end
79
+ end
80
+ end
81
+
82
+ Autoproj.user_config('automatic_osdeps')
83
+ end
84
+
29
85
  def self.initialize
30
86
  Autobuild::Reporting << Autoproj::Reporter.new
31
87
  if mail_config[:to]
@@ -34,6 +90,10 @@ module Autoproj
34
90
 
35
91
  Autoproj.load_config
36
92
 
93
+ if Autoproj.has_config_key?('prefix')
94
+ Autoproj.prefix = Autoproj.user_config('prefix')
95
+ end
96
+
37
97
  # If we are under rubygems, check that the GEM_HOME is right ...
38
98
  if $LOADED_FEATURES.any? { |l| l =~ /rubygems/ }
39
99
  if ENV['GEM_HOME'] != Autoproj.gem_home
@@ -50,6 +110,8 @@ module Autoproj
50
110
  Autobuild.srcdir = Autoproj.root_dir
51
111
  Autobuild.logdir = File.join(Autobuild.prefix, 'log')
52
112
 
113
+ handle_automatic_osdeps
114
+
53
115
  ruby = RbConfig::CONFIG['RUBY_INSTALL_NAME']
54
116
  if ruby != 'ruby'
55
117
  bindir = File.join(Autoproj.build_dir, 'bin')
@@ -282,6 +344,27 @@ module Autoproj
282
344
  selected_packages
283
345
  end
284
346
 
347
+ def self.verify_package_availability(pkg_name)
348
+ if reason = Autoproj.manifest.exclusion_reason(pkg_name)
349
+ raise ConfigError, "#{pkg_name} is excluded from the build: #{reason}"
350
+ end
351
+ pkg = Autobuild::Package[pkg_name]
352
+ if !pkg
353
+ raise ConfigError, "#{pkg_name} does not seem to exist"
354
+ end
355
+
356
+ # Verify that its dependencies are there, and add
357
+ # them to the selected_packages set so that they get
358
+ # imported as well
359
+ pkg.dependencies.each do |dep_name|
360
+ begin
361
+ verify_package_availability(dep_name)
362
+ rescue ConfigError => e
363
+ raise e, "#{pkg_name} depends on #{dep_name}, but #{e.message}"
364
+ end
365
+ end
366
+ end
367
+
285
368
  def self.import_packages(selected_packages)
286
369
  selected_packages = selected_packages.dup.
287
370
  map do |pkg_name|
@@ -309,6 +392,7 @@ module Autoproj
309
392
  Autobuild.do_update = old_update_flag
310
393
  end
311
394
 
395
+ known_available_packages = Set.new
312
396
  all_enabled_packages = Set.new
313
397
 
314
398
  package_queue = selected_packages.dup
@@ -320,6 +404,12 @@ module Autoproj
320
404
  delete_if { |pkg| all_enabled_packages.include?(pkg.name) }
321
405
  all_enabled_packages |= current_packages.map(&:name).to_set
322
406
 
407
+ # Recursively check that no package in the selection depend on
408
+ # excluded packages
409
+ current_packages.each do |pkg|
410
+ verify_package_availability(pkg.name)
411
+ end
412
+
323
413
  # We import first so that all packages can export the
324
414
  # additional targets they provide.
325
415
  current_packages.each do |pkg|
@@ -334,21 +424,14 @@ module Autoproj
334
424
  end
335
425
 
336
426
  current_packages.each do |pkg|
427
+ verify_package_availability(pkg.name)
337
428
  Rake::Task["#{pkg.name}-prepare"].invoke
338
429
 
339
430
  # Verify that its dependencies are there, and add
340
431
  # them to the selected_packages set so that they get
341
432
  # imported as well
342
433
  pkg.dependencies.each do |dep_name|
343
- if reason = Autoproj.manifest.exclusion_reason(dep_name)
344
- raise ConfigError, "#{pkg.name} depends on #{dep_name}, which is excluded from the build: #{reason}"
345
- end
346
- dep_pkg = Autobuild::Package[dep_name]
347
- if !dep_pkg
348
- raise ConfigError, "#{pkg.name} depends on #{dep_name}, but it does not seem to exist"
349
- end
350
-
351
- package_queue << dep_pkg
434
+ package_queue << Autobuild::Package[dep_name]
352
435
  end
353
436
  end
354
437
  end
@@ -630,6 +713,7 @@ where 'mode' is one of:
630
713
  Autobuild.do_update = false
631
714
  @update_os_dependencies = true
632
715
  Autobuild.do_build = false
716
+ Autoproj::OSDependencies.force_osdeps = true
633
717
  when "status"
634
718
  @only_status = true
635
719
  Autobuild.do_update = false
@@ -938,6 +938,7 @@ module Autoproj
938
938
  if dest != source.raw_local_dir
939
939
  FileUtils.rm_f symlink_dest
940
940
  end
941
+ FileUtils.ln_sf source.raw_local_dir, symlink_dest
941
942
  else
942
943
  FileUtils.rm_f symlink_dest
943
944
  FileUtils.ln_sf source.raw_local_dir, symlink_dest
@@ -1151,9 +1152,9 @@ module Autoproj
1151
1152
  begin
1152
1153
  package.depends_on name
1153
1154
  rescue Autobuild::ConfigException => e
1154
- raise ConfigError, "manifest #{manifest_path} of #{package.name} from #{source.name} lists '#{name}' as dependency, which is listed in the layout but has no autobuild definition"
1155
+ raise ConfigError, "manifest #{manifest_path} of #{package.name} from #{source.name} lists '#{name}' as dependency, which is listed in the layout but has no autobuild definition", e.backtrace
1155
1156
  rescue ConfigError => e
1156
- raise ConfigError, "manifest #{manifest_path} of #{package.name} from #{source.name} lists '#{name}' as dependency, but it is neither a normal package nor an osdeps package. osdeps reports: #{e.message}"
1157
+ raise ConfigError, "manifest #{manifest_path} of #{package.name} from #{source.name} lists '#{name}' as dependency, but it is neither a normal package nor an osdeps package. osdeps reports: #{e.message}", e.backtrace
1157
1158
  end
1158
1159
  end
1159
1160
  end
@@ -23,12 +23,14 @@ module Autoproj
23
23
  end
24
24
 
25
25
  def ask(current_value)
26
- default_value = if current_value then current_value.to_s
27
- elsif options[:default] then options[:default].to_str
28
- else ''
29
- end
30
-
31
- STDERR.print " #{doc} [#{default_value}] "
26
+ default_value =
27
+ if current_value then current_value.to_s
28
+ elsif options[:default] then options[:default].to_str
29
+ else ''
30
+ end
31
+
32
+ STDOUT.print " #{doc} [#{default_value}] "
33
+ STDOUT.flush
32
34
  answer = STDIN.readline.chomp
33
35
  if answer == ''
34
36
  answer = default_value
@@ -90,7 +92,11 @@ module Autoproj
90
92
  value = configure(key)
91
93
  else
92
94
  if !seen
93
- Autoproj.progress " #{@declared_options[key].doc}: #{value}"
95
+ doc = @declared_options[key].doc
96
+ if doc[-1, 1] != "?"
97
+ doc = "#{doc}:"
98
+ end
99
+ Autoproj.progress " #{doc} #{value}"
94
100
  @user_config[key] = [value, true]
95
101
  end
96
102
  value
@@ -102,6 +108,10 @@ module Autoproj
102
108
  @declared_options[name] = BuildOption.new(name, type, options, validator)
103
109
  end
104
110
 
111
+ def self.declared_option?(name)
112
+ @declared_options.has_key?(name)
113
+ end
114
+
105
115
  def self.configure(option_name)
106
116
  if opt = @declared_options[option_name]
107
117
  if current_value = @user_config[option_name]
@@ -15,6 +15,8 @@ module Autoproj
15
15
 
16
16
  class << self
17
17
  attr_reader :aliases
18
+ attr_accessor :force_osdeps
19
+ attr_accessor :gem_with_prerelease
18
20
  end
19
21
  @aliases = Hash.new
20
22
 
@@ -142,11 +144,13 @@ module Autoproj
142
144
  ['gentoo', [version]]
143
145
  elsif File.exists?('/etc/arch-release')
144
146
  ['arch', []]
145
- else
146
- raise ConfigError, "Unknown operating system"
147
147
  end
148
148
  end
149
149
 
150
+ if !@operating_system
151
+ return
152
+ end
153
+
150
154
  # Normalize the names to lowercase
151
155
  @operating_system =
152
156
  [@operating_system[0].downcase,
@@ -182,62 +186,118 @@ module Autoproj
182
186
  'arch' => 'pacman -Sy --noconfirm %s'
183
187
  }
184
188
 
185
- # Resolves the given OS dependencies into the actual packages that need
186
- # to be installed on this particular OS.
189
+ NO_PACKAGE = 0
190
+ WRONG_OS = 1
191
+ WRONG_OS_VERSION = 2
192
+ IGNORE = 3
193
+ PACKAGES = 4
194
+ SHELL_SNIPPET = 5
195
+ UNKNOWN_OS = 7
196
+ AVAILABLE = 10
197
+
198
+ # Check for the definition of +name+ for this operating system
187
199
  #
188
- # Raises ConfigError if some packages can't be found
189
- def resolve_os_dependencies(dependencies)
200
+ # It can return
201
+ #
202
+ # NO_PACKAGE::
203
+ # there are no package definition for +name
204
+ # UNKNOWN_OS::
205
+ # this is not an OS autoproj knows how to deal with
206
+ # WRONG_OS::
207
+ # there are a package definition, but not for this OS
208
+ # WRONG_OS_VERSION::
209
+ # there is a package definition for this OS, but not for this
210
+ # particular version of the OS
211
+ # IGNORE::
212
+ # there is a package definition that told us to ignore the package
213
+ # [PACKAGES, definition]::
214
+ # +definition+ is an array of package names that this OS's package
215
+ # manager can understand
216
+ # [SHELL_SNIPPET, definition]::
217
+ # +definition+ is a string which is a shell snippet that will install
218
+ # the package
219
+ def resolve_package(name)
190
220
  os_name, os_version = OSDependencies.operating_system
191
- if !OS_PACKAGE_INSTALL.has_key?(os_name)
192
- raise ConfigError, "I don't know how to install packages on #{os_name}"
221
+
222
+ dep_def = definitions[name]
223
+ if !dep_def
224
+ return NO_PACKAGE
193
225
  end
194
226
 
195
- os_packages = []
196
- shell_snippets = []
197
- dependencies.each do |name|
198
- dep_def = definitions[name]
199
- if !dep_def
200
- raise ConfigError, "I don't know how to install '#{name}'"
201
- end
227
+ if !os_name
228
+ return UNKNOWN_OS
229
+ end
230
+
231
+ # Find a matching entry for the OS name
232
+ os_entry = dep_def.find do |name_list, data|
233
+ name_list.split(',').
234
+ map(&:downcase).
235
+ any? { |n| n == os_name }
236
+ end
237
+
238
+ if !os_entry
239
+ return WRONG_OS
240
+ end
241
+
242
+ data = os_entry.last
202
243
 
203
- # Find a matching entry for the OS name
204
- os_entry = dep_def.find do |name_list, data|
205
- name_list.split(',').
244
+ # This package does not need to be installed on this operating system (example: build tools on Gentoo)
245
+ if !data || data == "ignore"
246
+ return IGNORE
247
+ end
248
+
249
+ if data.kind_of?(Hash)
250
+ version_entry = data.find do |version_list, data|
251
+ version_list.to_s.split(',').
206
252
  map(&:downcase).
207
- any? { |n| n == os_name }
253
+ any? do |v|
254
+ os_version.any? { |osv| Regexp.new(v) =~ osv }
255
+ end
208
256
  end
209
257
 
210
- if !os_entry
211
- raise ConfigError, "I don't know how to install '#{name}' on #{os_name}"
258
+ if !version_entry
259
+ return WRONG_OS_VERSION
212
260
  end
261
+ data = version_entry.last
262
+ end
213
263
 
214
- data = os_entry.last
215
-
216
- # This package does not need to be installed on this operating system (example: build tools on Gentoo)
217
- next if !data || data == "ignore"
264
+ if data.respond_to?(:to_ary)
265
+ return [PACKAGES, data]
266
+ elsif data.to_str =~ /\w+/
267
+ return [PACKAGES, [data.to_str]]
268
+ else
269
+ return [SHELL_SNIPPET, data.to_str]
270
+ end
271
+ end
218
272
 
219
- if data.kind_of?(Hash)
220
- version_entry = data.find do |version_list, data|
221
- version_list.to_s.split(',').
222
- map(&:downcase).
223
- any? do |v|
224
- os_version.any? { |osv| Regexp.new(v) =~ osv }
225
- end
226
- end
273
+ # Resolves the given OS dependencies into the actual packages that need
274
+ # to be installed on this particular OS.
275
+ #
276
+ # Raises ConfigError if some packages can't be found
277
+ def resolve_os_dependencies(dependencies)
278
+ os_name, os_version = OSDependencies.operating_system
227
279
 
228
- if !version_entry
229
- raise ConfigError, "I don't know how to install '#{name}' on this specific version of #{os_name} (#{os_version.join(", ")})"
230
- end
231
- data = version_entry.last
280
+ os_packages = []
281
+ shell_snippets = []
282
+ dependencies.each do |name|
283
+ result = resolve_package(name)
284
+ if result == NO_PACKAGE
285
+ raise ConfigError, "there is no osdeps definition for #{name}"
286
+ elsif result == WRONG_OS
287
+ raise ConfigError, "there is an osdeps definition for #{name}, but not for this operating system"
288
+ elsif result == WRONG_OS_VERSION
289
+ raise ConfigError, "there is an osdeps definition for #{name}, but no for this particular operating system version"
290
+ elsif result == IGNORE
291
+ next
292
+ elsif result[0] == PACKAGES
293
+ os_packages.concat(result[1])
294
+ elsif result[0] == SHELL_SNIPPET
295
+ shell_snippets << result[1]
232
296
  end
297
+ end
233
298
 
234
- if data.respond_to?(:to_ary)
235
- os_packages.concat data.to_ary
236
- elsif data.to_str =~ /\w+/
237
- os_packages << data.to_str
238
- else
239
- shell_snippets << data.to_str
240
- end
299
+ if !OS_PACKAGE_INSTALL.has_key?(os_name)
300
+ raise ConfigError, "I don't know how to install packages on #{os_name}"
241
301
  end
242
302
 
243
303
  return os_packages, shell_snippets
@@ -254,14 +314,27 @@ module Autoproj
254
314
  "\n" + shell_snippets.join("\n")
255
315
  end
256
316
 
257
- # Returns true if there is an operating-system package with that name,
258
- # and false otherwise
317
+ # Returns true if +name+ is an acceptable OS package for this OS and
318
+ # version
259
319
  def has?(name)
320
+ availability_of(name) == AVAILABLE
321
+ end
322
+
323
+ # If +name+ is an osdeps that is available for this operating system,
324
+ # returns AVAILABLE. Otherwise, returns the same error code than
325
+ # resolve_package.
326
+ def availability_of(name)
260
327
  osdeps, gemdeps = partition_packages([name].to_set)
261
- resolve_os_dependencies(osdeps)
262
- true
263
- rescue ConfigError
264
- false
328
+ if !osdeps.empty?
329
+ status = resolve_package(name)
330
+ if status.respond_to?(:to_ary) || status == IGNORE
331
+ AVAILABLE
332
+ else
333
+ status
334
+ end
335
+ else
336
+ AVAILABLE
337
+ end
265
338
  end
266
339
 
267
340
  # call-seq:
@@ -282,12 +355,10 @@ module Autoproj
282
355
  package_set.to_set.each do |name|
283
356
  pkg_def = definitions[name]
284
357
  if !pkg_def
285
- msg = "I know nothing about a prepackaged software called '#{name}'"
286
- if pkg_names = package_osdeps[name]
287
- msg += ", it is listed as dependency of the following package(s): #{pkg_names.join(", ")}"
288
- end
289
-
290
- raise ConfigError, msg
358
+ # Error cases are taken care of later, because that is were
359
+ # the automatic/manual osdeps logic lies
360
+ osdeps << name
361
+ next
291
362
  end
292
363
 
293
364
  pkg_def = pkg_def.dup
@@ -298,6 +369,9 @@ module Autoproj
298
369
  when "gem" then
299
370
  gems << name
300
371
  else
372
+ # This is *not* handled later, as is the absence of a
373
+ # package definition. The reason is that it is a bad
374
+ # configuration file, and should be fixed by the user
301
375
  raise ConfigError, "unknown OS-independent package management type #{pkg_def} for #{name}"
302
376
  end
303
377
  else
@@ -328,19 +402,123 @@ module Autoproj
328
402
  end
329
403
  end
330
404
 
405
+ def filter_uptodate_gems(gems)
406
+ Autobuild.progress "looking for RubyGems updates"
407
+
408
+ # Don't install gems that are already there ...
409
+ gems = gems.dup
410
+ gems.delete_if do |name|
411
+ version_requirements = Gem::Requirement.default
412
+ installed = Gem.source_index.find_name(name, version_requirements)
413
+ if !installed.empty? && Autobuild.do_update
414
+ # Look if we can update the package ...
415
+ dep = Gem::Dependency.new(name, version_requirements)
416
+ available = gem_fetcher.find_matching(dep)
417
+ installed_version = installed.map(&:version).max
418
+ available_version = available.map { |(name, v), source| v }.max
419
+ needs_update = (available_version > installed_version)
420
+ !needs_update
421
+ else
422
+ !installed.empty?
423
+ end
424
+ end
425
+ gems
426
+ end
427
+
428
+ AUTOMATIC = true
429
+ MANUAL = false
430
+ WAIT = :wait
431
+ ASK = :ask
432
+
433
+ def automatic_osdeps_mode
434
+ if mode = ENV['AUTOPROJ_AUTOMATIC_OSDEPS']
435
+ mode =
436
+ if mode == 'true' then AUTOMATIC
437
+ elsif mode == 'false' then MANUAL
438
+ elsif mode == 'wait' then WAIT
439
+ else ASK
440
+ end
441
+ Autoproj.change_option('automatic_osdeps', mode, true)
442
+ mode
443
+ else
444
+ Autoproj.user_config('automatic_osdeps')
445
+ end
446
+ end
447
+
331
448
  # Requests the installation of the given set of packages
332
449
  def install(packages, package_osdeps = Hash.new)
450
+ os_def = OSDependencies.operating_system
333
451
  osdeps, gems = partition_packages(packages, package_osdeps)
452
+ gems = filter_uptodate_gems(gems)
453
+ if osdeps.empty? && gems.empty?
454
+ return
455
+ end
456
+
457
+ if automatic_osdeps_mode == AUTOMATIC && !os_def && !osdeps.empty?
458
+ puts
459
+ puts Autoproj.color("==============================", :bold)
460
+ puts Autoproj.color("The packages that will be built require some other software to be installed", :bold)
461
+ puts " " + osdeps.join("\n ")
462
+ puts Autoproj.color("==============================", :bold)
463
+ puts
464
+ end
465
+
466
+ if !OSDependencies.force_osdeps && automatic_osdeps_mode != AUTOMATIC
467
+ puts
468
+ puts Autoproj.color("==============================", :bold)
469
+ puts Autoproj.color("The packages that will be built require some other software to be installed", :bold)
470
+ puts
471
+ if !osdeps.empty?
472
+ puts "From the operating system:"
473
+ puts " " + osdeps.join("\n ")
474
+ puts
475
+ end
476
+ if !gems.empty?
477
+ puts "From RubyGems:"
478
+ puts " " + gems.join("\n ")
479
+ puts
480
+ end
481
+
482
+ if automatic_osdeps_mode == ASK
483
+ print "Should I install these packages ? [yes] "
484
+ STDOUT.flush
485
+ do_osdeps = nil
486
+ while do_osdeps.nil?
487
+ answer = STDIN.readline.chomp
488
+ if answer == ''
489
+ do_osdeps = true
490
+ elsif answer == "no"
491
+ do_osdeps = false
492
+ elsif answer == 'yes'
493
+ do_osdeps = true
494
+ else
495
+ print "invalid answer. Please answer with 'yes' or 'no' "
496
+ STDOUT.flush
497
+ end
498
+ end
499
+ else
500
+ puts "Since you requested autoproj to not handle the osdeps automatically, you have to"
501
+ puts "do it yourself. Alternatively, you can run 'autoproj osdeps' and/or change to"
502
+ puts "automatic osdeps handling by running an autoproj operation with the --reconfigure"
503
+ puts "option (e.g. autoproj build --reconfigure)"
504
+ puts Autoproj.color("==============================", :bold)
505
+ puts
506
+
507
+ if automatic_osdeps_mode == WAIT
508
+ print "Press ENTER to continue "
509
+ STDOUT.flush
510
+ STDIN.readline
511
+ end
512
+ end
513
+
514
+ if !do_osdeps
515
+ return
516
+ end
517
+ end
334
518
 
335
519
  did_something = false
336
520
 
337
- # Ideally, we would feed the OS dependencies to rosdep.
338
- # Unfortunately, this is C++ code and I don't want to install the
339
- # whole ROS stack just for rosdep ...
340
- #
341
- # So, for now, reimplement rosdep by ourselves. Given how things
342
- # are done, this is actually not so hard.
343
- if !osdeps.empty?
521
+ if os_def && !osdeps.empty?
344
522
  shell_script = generate_os_script(osdeps)
345
523
  if Autoproj.verbose
346
524
  Autoproj.progress "Installing non-ruby OS dependencies with"
@@ -360,35 +538,25 @@ module Autoproj
360
538
  end
361
539
 
362
540
  if !gems.empty?
363
- Autobuild.progress "looking for RubyGems updates"
364
- # Don't install gems that are already there ...
365
- gems.delete_if do |name|
366
- version_requirements = Gem::Requirement.default
367
- installed = Gem.source_index.find_name(name, version_requirements)
368
- if !installed.empty? && Autobuild.do_update
369
- # Look if we can update the package ...
370
- dep = Gem::Dependency.new(name, version_requirements)
371
- available = gem_fetcher.find_matching(dep)
372
- installed_version = installed.map(&:version).max
373
- available_version = available.map { |(name, v), source| v }.max
374
- needs_update = (available_version > installed_version)
375
- !needs_update
376
- else
377
- !installed.empty?
378
- end
379
- end
541
+ gems = filter_uptodate_gems(gems)
380
542
  end
381
543
 
382
544
  # Now install what is left
383
545
  if !gems.empty?
384
546
  guess_gem_program
385
-
386
547
  if Autoproj.verbose
387
548
  Autoproj.progress "Installing rubygems dependencies with"
388
549
  Autoproj.progress "gem install #{gems.join(" ")}"
389
550
  end
551
+
552
+ cmdline = [Autobuild.tool('gem'), 'install']
553
+ if Autobuild::OSDependencies.gem_with_prerelease
554
+ cmdline << "--prerelease"
555
+ end
556
+ cmdline.concat(gems)
557
+
390
558
  Autobuild.progress "installing/updating RubyGems dependencies: #{gems.join(", ")}"
391
- Autobuild::Subprocess.run 'autoproj', 'osdeps', Autobuild.tool('gem'), 'install', *gems
559
+ Autobuild::Subprocess.run 'autoproj', 'osdeps', *cmdline
392
560
  did_something ||= true
393
561
  end
394
562