autoproj 2.0.0.b7 → 2.0.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.
Files changed (60) hide show
  1. checksums.yaml +4 -4
  2. data/.gitattributes +1 -0
  3. data/.gitignore +8 -0
  4. data/.travis.yml +5 -0
  5. data/Gemfile +6 -0
  6. data/README.md +4 -0
  7. data/Rakefile +40 -81
  8. data/autoproj.gemspec +29 -0
  9. data/lib/autoproj/cli/cache.rb +7 -2
  10. data/lib/autoproj/cli/main.rb +46 -25
  11. data/lib/autoproj/cli/main_test.rb +6 -4
  12. data/lib/autoproj/cli/status.rb +2 -2
  13. data/lib/autoproj/configuration.rb +5 -0
  14. data/lib/autoproj/git_server_configuration.rb +117 -0
  15. data/lib/autoproj/osdeps.rb +14 -914
  16. data/lib/autoproj/package_managers/apt_dpkg_manager.rb +70 -0
  17. data/lib/autoproj/package_managers/emerge_manager.rb +14 -0
  18. data/lib/autoproj/package_managers/gem_manager.rb +313 -0
  19. data/lib/autoproj/package_managers/homebrew_manager.rb +44 -0
  20. data/lib/autoproj/package_managers/manager.rb +45 -0
  21. data/lib/autoproj/package_managers/pacman_manager.rb +14 -0
  22. data/lib/autoproj/package_managers/pip_manager.rb +86 -0
  23. data/lib/autoproj/package_managers/pkg_manager.rb +14 -0
  24. data/lib/autoproj/package_managers/port_manager.rb +14 -0
  25. data/lib/autoproj/package_managers/shell_script_manager.rb +207 -0
  26. data/lib/autoproj/package_managers/unknown_os_manager.rb +42 -0
  27. data/lib/autoproj/package_managers/yum_manager.rb +56 -0
  28. data/lib/autoproj/package_managers/zypper_manager.rb +43 -0
  29. data/lib/autoproj/package_manifest.rb +1 -1
  30. data/lib/autoproj/test.rb +13 -14
  31. data/lib/autoproj/variable_expansion.rb +4 -2
  32. data/lib/autoproj/version.rb +1 -1
  33. data/lib/autoproj/workspace.rb +5 -1
  34. data/manifest.xml +20 -0
  35. metadata +73 -87
  36. data/.gemtest +0 -0
  37. data/Manifest.txt +0 -105
  38. data/test/data/empty_manifest.xml +0 -2
  39. data/test/data/full_manifest.xml +0 -19
  40. data/test/data/invalid_manifest.xml +0 -3
  41. data/test/data/os_release.with_complex_version_field +0 -3
  42. data/test/data/os_release.with_duplicate_values +0 -3
  43. data/test/data/os_release.with_missing_optional_fields +0 -2
  44. data/test/data/os_release.with_quoted_and_unquoted_fields +0 -2
  45. data/test/data/test_manifest/autoproj/local_set/local.autobuild +0 -0
  46. data/test/data/test_manifest/autoproj/local_set/source.yml +0 -1
  47. data/test/data/test_manifest/autoproj/manifest +0 -7
  48. data/test/ops/test_configuration.rb +0 -20
  49. data/test/ops/test_snapshot.rb +0 -26
  50. data/test/package_managers/apt-dpkg-status +0 -41
  51. data/test/package_managers/apt-dpkg-status.installed-last +0 -27
  52. data/test/package_managers/apt-dpkg-status.noninstalled-last +0 -12
  53. data/test/package_managers/test_apt_dpkg_manager.rb +0 -41
  54. data/test/package_managers/test_gem.rb +0 -156
  55. data/test/package_managers/test_pip.rb +0 -42
  56. data/test/test_manifest.rb +0 -48
  57. data/test/test_os_dependencies.rb +0 -586
  58. data/test/test_package.rb +0 -30
  59. data/test/test_package_manifest.rb +0 -65
  60. data/test/test_vcs_definition.rb +0 -46
@@ -1,923 +1,23 @@
1
1
  require 'tempfile'
2
2
  require 'json'
3
- module Autoproj
4
- # Module that contains the package manager implementations for the
5
- # OSDependencies class
6
- module PackageManagers
7
- # Base class for all package managers. Subclasses must add the
8
- # #install(packages) method and may add the
9
- # #filter_uptodate_packages(packages) method
10
- #
11
- # Package managers must be registered in PACKAGE_HANDLERS and
12
- # (if applicable) OS_PACKAGE_HANDLERS.
13
- class Manager
14
- # @return [Array<String>] the various names this package manager is
15
- # known about
16
- attr_reader :names
17
-
18
- attr_writer :enabled
19
- def enabled?; !!@enabled end
20
-
21
- attr_writer :silent
22
- def silent?; !!@silent end
23
-
24
- # Create a package manager registered with various names
25
- #
26
- # @param [Array<String>] names the package manager names. It MUST be
27
- # different from the OS names that autoproj uses. See the comment
28
- # for OS_PACKAGE_HANDLERS for an explanation
29
- def initialize(names = [])
30
- @names = names.dup
31
- @enabled = true
32
- @silent = true
33
- end
34
-
35
- # The primary name for this package manager
36
- def name
37
- names.first
38
- end
39
-
40
- # Overload to perform initialization of environment variables in
41
- # order to have a properly functioning package manager
42
- #
43
- # This is e.g. needed for python pip or rubygems
44
- def self.initialize_environment(_env = nil, _manifest = nil, _root_dir = Autoproj.root_dir)
45
- end
46
- end
47
-
48
- # Dummy package manager used for unknown OSes. It simply displays a
49
- # message to the user when packages are needed
50
- class UnknownOSManager < Manager
51
- def initialize
52
- super(['unknown'])
53
- @installed_osdeps = Set.new
54
- end
55
-
56
- def osdeps_interaction_unknown_os(osdeps)
57
- puts <<-EOMSG
58
- #{Autoproj.color("The build process requires some other software packages to be installed on our operating system", :bold)}
59
- #{Autoproj.color("If they are already installed, simply ignore this message", :red)}
60
-
61
- #{osdeps.to_a.sort.join("\n ")}
62
-
63
- EOMSG
64
- print Autoproj.color("Press ENTER to continue", :bold)
65
- STDOUT.flush
66
- STDIN.readline
67
- puts
68
- nil
69
- end
70
-
71
- def install(osdeps)
72
- if silent?
73
- return false
74
- else
75
- osdeps = osdeps.to_set
76
- osdeps -= @installed_osdeps
77
- if !osdeps.empty?
78
- result = osdeps_interaction_unknown_os(osdeps)
79
- end
80
- @installed_osdeps |= osdeps
81
- return result
82
- end
83
- end
84
- end
85
-
86
- # Base class for all package managers that simply require the call of a
87
- # shell script to install packages (e.g. yum, apt, ...)
88
- class ShellScriptManager < Manager
89
- def self.execute(script, with_locking, with_root)
90
- if with_locking
91
- File.open('/tmp/autoproj_osdeps_lock', 'w') do |lock_io|
92
- begin
93
- while !lock_io.flock(File::LOCK_EX | File::LOCK_NB)
94
- Autoproj.message " waiting for other autoproj instances to finish their osdeps installation"
95
- sleep 5
96
- end
97
- return execute(script, false,with_root)
98
- ensure
99
- lock_io.flock(File::LOCK_UN)
100
- end
101
- end
102
- end
103
-
104
- sudo = Autobuild.tool_in_path('sudo')
105
- Tempfile.open('osdeps_sh') do |io|
106
- io.puts "#! /bin/bash"
107
- io.puts GAIN_ROOT_ACCESS % [sudo] if with_root
108
- io.write script
109
- io.flush
110
- Autobuild::Subprocess.run 'autoproj', 'osdeps', '/bin/bash', io.path
111
- end
112
- end
113
-
114
- GAIN_ROOT_ACCESS = <<-EOSCRIPT
115
- # Gain root access using sudo
116
- if test `id -u` != "0"; then
117
- exec %s /bin/bash $0 "$@"
118
-
119
- fi
120
- EOSCRIPT
121
-
122
- # Overrides the {#needs_locking?} flag
123
- attr_writer :needs_locking
124
- # Whether two autoproj instances can run this package manager at the
125
- # same time
126
- #
127
- # This declares if this package manager cannot be used concurrently.
128
- # If it is the case, autoproj will ensure that there is no two
129
- # autoproj instances running this package manager at the same time
130
- #
131
- # @return [Boolean]
132
- # @see needs_locking=
133
- def needs_locking?; !!@needs_locking end
134
-
135
- # Overrides the {#needs_root?} flag
136
- attr_writer :needs_root
137
- # Whether this package manager needs root access.
138
- #
139
- # This declares if the command line(s) for this package manager
140
- # should be started as root. Root access is provided using sudo
141
- #
142
- # @return [Boolean]
143
- # @see needs_root=
144
- def needs_root?; !!@needs_root end
145
-
146
- # Command line used by autoproj to install packages
147
- #
148
- # Since it is to be used for automated install by autoproj, it
149
- # should not require any interaction with the user. When generating
150
- # the command line, the %s slot is replaced by the quoted package
151
- # name(s).
152
- #
153
- # @return [String] a command line pattern that allows to install
154
- # packages without user interaction. It is used when a package
155
- # should be installed by autoproj automatically
156
- attr_reader :auto_install_cmd
157
- # Command line displayed to the user to install packages
158
- #
159
- # When generating the command line, the %s slot is replaced by the
160
- # quoted package name(s).
161
- #
162
- # @return [String] a command line pattern that allows to install
163
- # packages with user interaction. It is displayed to the
164
- # user when it chose to not let autoproj install packages for this
165
- # package manager automatically
166
- attr_reader :user_install_cmd
167
-
168
- # @param [Array<String>] names the package managers names, see
169
- # {#names}
170
- # @param [Boolean] needs_locking whether this package manager can be
171
- # started by two separate autoproj instances at the same time. See
172
- # {#needs_locking?}
173
- # @param [String] user_install_cmd the user-visible command line. See
174
- # {#user_install_cmd}
175
- # @param [String] auto_install_cmd the command line used by autoproj
176
- # itself, see {#auto_install_cmd}.
177
- # @param [Boolean] needs_root if the command lines should be started
178
- # as root or not. See {#needs_root?}
179
- def initialize(names, needs_locking, user_install_cmd, auto_install_cmd,needs_root=true)
180
- super(names)
181
- @needs_locking, @user_install_cmd, @auto_install_cmd,@needs_root =
182
- needs_locking, user_install_cmd, auto_install_cmd, needs_root
183
- end
184
-
185
- # Generate the shell script that would allow the user to install
186
- # the given packages
187
- #
188
- # @param [Array<String>] os_packages the name of the packages to be
189
- # installed
190
- # @option options [String] :user_install_cmd (#user_install_cmd) the
191
- # command-line pattern that should be used to generate the script.
192
- # If given, it overrides the default value stored in
193
- # {#user_install_cmd]
194
- def generate_user_os_script(os_packages, options = Hash.new)
195
- user_install_cmd = options[:user_install_cmd] || self.user_install_cmd
196
- if user_install_cmd
197
- (user_install_cmd % [os_packages.join("' '")])
198
- else generate_auto_os_script(os_packages)
199
- end
200
- end
201
-
202
- # Generate the shell script that should be executed by autoproj to
203
- # install the given packages
204
- #
205
- # @param [Array<String>] os_packages the name of the packages to be
206
- # installed
207
- # @option options [String] :auto_install_cmd (#auto_install_cmd) the
208
- # command-line pattern that should be used to generate the script.
209
- # If given, it overrides the default value stored in
210
- # {#auto_install_cmd]
211
- def generate_auto_os_script(os_packages, options = Hash.new)
212
- auto_install_cmd = options[:auto_install_cmd] || self.auto_install_cmd
213
- (auto_install_cmd % [os_packages.join("' '")])
214
- end
215
-
216
- # Handles interaction with the user
217
- #
218
- # This method will verify whether the user required autoproj to
219
- # install packages from this package manager automatically. It
220
- # displays a relevant message if it is not the case.
221
- #
222
- # @return [Boolean] true if the packages should be installed
223
- # automatically, false otherwise
224
- def osdeps_interaction(os_packages, shell_script)
225
- if OSDependencies.force_osdeps
226
- return true
227
- elsif enabled?
228
- return true
229
- elsif silent?
230
- return false
231
- end
232
-
233
- # We're asked to not install the OS packages but to display them
234
- # anyway, do so now
235
- puts <<-EOMSG
236
-
237
- #{Autoproj.color("The build process and/or the packages require some other software to be installed", :bold)}
238
- #{Autoproj.color("and you required autoproj to not install them itself", :bold)}
239
- #{Autoproj.color("\nIf these packages are already installed, simply ignore this message\n", :red) if !respond_to?(:filter_uptodate_packages)}
240
- The following packages are available as OS dependencies, i.e. as prebuilt
241
- packages provided by your distribution / operating system. You will have to
242
- install them manually if they are not already installed
243
-
244
- #{os_packages.sort.join("\n ")}
245
-
246
- the following command line(s) can be run as root to install them:
247
-
248
- #{shell_script.split("\n").join("\n| ")}
249
-
250
- EOMSG
251
- print " #{Autoproj.color("Press ENTER to continue ", :bold)}"
252
- STDOUT.flush
253
- STDIN.readline
254
- puts
255
- false
256
- end
257
-
258
- # Install packages using this package manager
259
- #
260
- # @param [Array<String>] packages the name of the packages that
261
- # should be installed
262
- # @option options [String] :user_install_cmd (#user_install_cmd) the
263
- # command line that should be displayed to the user to install said
264
- # packages. See the option in {#generate_user_os_script}
265
- # @option options [String] :auto_install_cmd (#auto_install_cmd) the
266
- # command line that should be used by autoproj to install said
267
- # packages. See the option in {#generate_auto_os_script}
268
- # @return [Boolean] true if packages got installed, false otherwise
269
- def install(packages, options = Hash.new)
270
- handled_os = OSDependencies.supported_operating_system?
271
- if handled_os
272
- shell_script = generate_auto_os_script(packages, options)
273
- user_shell_script = generate_user_os_script(packages, options)
274
- end
275
- if osdeps_interaction(packages, user_shell_script)
276
- Autoproj.message " installing OS packages: #{packages.sort.join(", ")}"
277
-
278
- if Autoproj.verbose
279
- Autoproj.message "Generating installation script for non-ruby OS dependencies"
280
- Autoproj.message shell_script
281
- end
282
- ShellScriptManager.execute(shell_script, needs_locking?,needs_root?)
283
- return true
284
- end
285
- false
286
- end
287
- end
288
-
289
- # Package manager interface for systems that use port (i.e. MacPorts/Darwin) as
290
- # their package manager
291
- class PortManager < ShellScriptManager
292
- def initialize
293
- super(['macports'], true,
294
- "port install '%s'",
295
- "port install '%s'")
296
- end
297
- end
298
-
299
- # Package manager interface for Mac OS using homebrew as
300
- # its package manager
301
- class HomebrewManager < ShellScriptManager
302
- def initialize
303
- super(['brew'], true,
304
- "brew install '%s'",
305
- "brew install '%s'",
306
- false)
307
- end
308
-
309
- def filter_uptodate_packages(packages, options = Hash.new)
310
- # TODO there might be duplicates in packages which should be fixed
311
- # somewhere else
312
- packages = packages.uniq
313
- result = `brew info --json=v1 '#{packages.join("' '")}'`
314
- result = begin
315
- JSON.parse(result)
316
- rescue JSON::ParserError
317
- if result && !result.empty?
318
- Autoproj.warn "Error while parsing result of brew info --json=v1"
319
- else
320
- # one of the packages is unknown fallback to install all
321
- # packaes which will complain about it
322
- end
323
- return packages
324
- end
325
- # fall back if something else went wrong
326
- if packages.size != result.size
327
- Autoproj.warn "brew info returns less or more packages when requested. Falling back to install all packages"
328
- return packages
329
- end
330
-
331
- new_packages = []
332
- result.each do |pkg|
333
- new_packages << pkg["name"] if pkg["installed"].empty?
334
- end
335
- new_packages
336
- end
337
- end
338
-
339
- # Package manager interface for systems that use pacman (i.e. arch) as
340
- # their package manager
341
- class PacmanManager < ShellScriptManager
342
- def initialize
343
- super(['pacman'], true,
344
- "pacman -Sy --needed '%s'",
345
- "pacman -Sy --needed --noconfirm '%s'")
346
- end
347
- end
348
-
349
- # Package manager interface for systems that use emerge (i.e. gentoo) as
350
- # their package manager
351
- class EmergeManager < ShellScriptManager
352
- def initialize
353
- super(['emerge'], true,
354
- "emerge '%s'",
355
- "emerge --noreplace '%s'")
356
- end
357
- end
358
- # Package manager interface for systems that use pkg (i.e. FreeBSD) as
359
- # their package manager
360
- class PkgManager < ShellScriptManager
361
- def initialize
362
- super(['pkg'], true,
363
- "pkg install -y '%s'",
364
- "pkg install -y '%s'")
365
- end
366
- end
367
-
368
- #Package manger for OpenSuse and Suse (untested)
369
- class ZypperManager < ShellScriptManager
370
- def initialize
371
- super(['zypper'], true,
372
- "zypper install '%s'",
373
- "zypper -n install '%s'")
374
- end
375
-
376
- def filter_uptodate_packages(packages, options = Hash.new)
377
- result = `LANG=C rpm -q --whatprovides '#{packages.join("' '")}'`
378
- has_all_pkgs = $?.success?
379
-
380
- if !has_all_pkgs
381
- return packages # let zypper filter, we need root now anyways
382
- else
383
- return []
384
- end
385
- end
386
-
387
- def install(packages)
388
- patterns, packages = packages.partition { |pkg| pkg =~ /^@/ }
389
- patterns = patterns.map { |str| str[1..-1] }
390
- result = false
391
- if !patterns.empty?
392
- result |= super(patterns,
393
- :auto_install_cmd => "zypper --non-interactive install --type pattern '%s'",
394
- :user_install_cmd => "zypper install --type pattern '%s'")
395
- end
396
- if !packages.empty?
397
- result |= super(packages)
398
- end
399
- if result
400
- # Invalidate caching of installed packages, as we just
401
- # installed new packages !
402
- @installed_packages = nil
403
- end
404
- end
405
- end
406
-
407
- # Package manager interface for systems that use yum
408
- class YumManager < ShellScriptManager
409
- def initialize
410
- super(['yum'], true,
411
- "yum install '%s'",
412
- "yum install -y '%s'")
413
- end
414
-
415
- def filter_uptodate_packages(packages, options = Hash.new)
416
- result = `LANG=C rpm -q --queryformat "%{NAME}\n" '#{packages.join("' '")}'`
417
-
418
- installed_packages = []
419
- new_packages = []
420
- result.split("\n").each_with_index do |line, index|
421
- line = line.strip
422
- if line =~ /package (.*) is not installed/
423
- package_name = $1
424
- if !packages.include?(package_name) # something is wrong, fallback to installing everything
425
- return packages
426
- end
427
- new_packages << package_name
428
- else
429
- package_name = line.strip
430
- if !packages.include?(package_name) # something is wrong, fallback to installing everything
431
- return packages
432
- end
433
- installed_packages << package_name
434
- end
435
- end
436
- new_packages
437
- end
438
-
439
- def install(packages)
440
- patterns, packages = packages.partition { |pkg| pkg =~ /^@/ }
441
- patterns = patterns.map { |str| str[1..-1] }
442
- result = false
443
- if !patterns.empty?
444
- result |= super(patterns,
445
- :auto_install_cmd => "yum groupinstall -y '%s'",
446
- :user_install_cmd => "yum groupinstall '%s'")
447
- end
448
- if !packages.empty?
449
- result |= super(packages)
450
- end
451
- if result
452
- # Invalidate caching of installed packages, as we just
453
- # installed new packages !
454
- @installed_packages = nil
455
- end
456
- end
457
- end
458
-
459
- # Package manager interface for systems that use APT and dpkg for
460
- # package management
461
- class AptDpkgManager < ShellScriptManager
462
- attr_accessor :status_file
463
-
464
- def initialize(status_file = "/var/lib/dpkg/status")
465
- @status_file = status_file
466
- super(['apt-dpkg'], true,
467
- "apt-get install '%s'",
468
- "export DEBIAN_FRONTEND=noninteractive; apt-get install -y '%s'")
469
- end
470
-
471
- # On a dpkg-enabled system, checks if the provided package is installed
472
- # and returns true if it is the case
473
- def installed?(package_name)
474
- if !@installed_packages
475
- @installed_packages = Set.new
476
- dpkg_status = File.readlines(status_file)
477
- dpkg_status << ""
478
-
479
- current_packages = []
480
- is_installed = false
481
- dpkg_status.each do |line|
482
- line = line.chomp
483
- line = line.encode( "UTF-8", "binary", :invalid => :replace, :undef => :replace)
484
- if line == ""
485
- if is_installed
486
- current_packages.each do |pkg|
487
- @installed_packages << pkg
488
- end
489
- is_installed = false
490
- end
491
- current_packages.clear
492
- elsif line =~ /Package: (.*)$/
493
- current_packages << $1
494
- elsif line =~ /Provides: (.*)$/
495
- current_packages.concat($1.split(',').map(&:strip))
496
- elsif line == "Status: install ok installed"
497
- is_installed = true
498
- end
499
- end
500
- end
501
-
502
- if package_name =~ /^(\w[a-z0-9+-.]+)/
503
- @installed_packages.include?($1)
504
- else
505
- Autoproj.warn "#{package_name} is not a valid Debian package name"
506
- false
507
- end
508
- end
509
-
510
- def install(packages)
511
- if super
512
- # Invalidate caching of installed packages, as we just
513
- # installed new packages !
514
- @installed_packages = nil
515
- end
516
- end
517
-
518
- def filter_uptodate_packages(packages, options = Hash.new)
519
- packages.find_all do |package_name|
520
- !installed?(package_name)
521
- end
522
- end
523
- end
524
-
525
- # Package manager interface for the RubyGems system
526
- class GemManager < Manager
527
- class << self
528
- attr_writer :with_prerelease
529
- attr_accessor :with_doc
530
- end
531
- @with_prerelease = false
532
- @with_doc = false
533
-
534
- def self.with_prerelease(*value)
535
- if value.empty?
536
- @with_prerelease
537
- else
538
- begin
539
- saved_flag = @with_prerelease
540
- @with_prerelease = value.first
541
- yield
542
- ensure
543
- @with_prerelease = saved_flag
544
- end
545
- end
546
- end
547
-
548
- # Filters all paths that come from other autoproj installations out
549
- # of GEM_PATH
550
- def self.initialize_environment(env = Autobuild.env, manifest = Autoproj.manifest, root_dir = Autoproj.root_dir)
551
- env.original_env['GEM_PATH'] =
552
- (env['GEM_PATH'] || "").split(File::PATH_SEPARATOR).find_all do |p|
553
- !Autoproj.in_autoproj_installation?(p)
554
- end.join(File::PATH_SEPARATOR)
555
- env.inherit 'GEM_PATH'
556
- env.init_from_env 'GEM_PATH'
557
-
558
- orig_gem_path = env.original_env['GEM_PATH'].split(File::PATH_SEPARATOR)
559
- env.system_env['GEM_PATH'] = Gem.default_path
560
- env.original_env['GEM_PATH'] = orig_gem_path.join(File::PATH_SEPARATOR)
561
-
562
- manifest.each_reused_autoproj_installation do |p|
563
- p_gems = File.join(p, '.gems')
564
- if File.directory?(p_gems)
565
- env.push_path 'GEM_PATH', p_gems
566
- env.push_path 'PATH', File.join(p_gems, 'bin')
567
- end
568
- end
569
-
570
- @gem_home = (ENV['AUTOPROJ_GEM_HOME'] || File.join(root_dir, ".gems"))
571
- env.push_path 'GEM_PATH', gem_home
572
- env.set 'GEM_HOME', gem_home
573
- env.push_path 'PATH', "#{gem_home}/bin"
574
-
575
- # Now, reset the directories in our own RubyGems instance
576
- Gem.paths = env.resolved_env
577
-
578
- use_cache_dir
579
- end
580
-
581
- # Override the gem home detected by {initialize_environment}, or set
582
- # it in cases where calling {initialize_environment} is not possible
583
- def self.gem_home=(gem_home)
584
- @gem_home = gem_home
585
- end
586
-
587
- # A global cache directory that should be used to avoid
588
- # re-downloading gems
589
- def self.cache_dir
590
- if dir = ENV['AUTOBUILD_CACHE_DIR']
591
- dir = File.join(dir, 'gems')
592
- FileUtils.mkdir_p dir
593
- dir
594
- end
595
- end
596
-
597
- def self.use_cache_dir
598
- # If there is a cache directory, make sure .gems/cache points to
599
- # it (there are no programmatic ways to override this)
600
- if cache = cache_dir
601
- gem_cache_dir = File.join(gem_home, 'cache')
602
- if !File.symlink?(gem_cache_dir) || File.readlink(gem_cache_dir) != cache
603
- FileUtils.mkdir_p gem_home
604
- FileUtils.rm_rf gem_cache_dir
605
- Autoproj.create_symlink(cache, gem_cache_dir)
606
- end
607
- end
608
- end
609
-
610
- # Return the directory in which RubyGems package should be installed
611
- def self.gem_home
612
- @gem_home
613
- end
614
-
615
- # Returns the set of default options that are added to gem
616
- #
617
- # By default, we add --no-user-install to un-break distributions
618
- # like Arch that set --user-install by default (thus disabling the
619
- # role of GEM_HOME)
620
- def self.default_install_options
621
- @default_install_options ||= ['--no-user-install', '--no-format-executable']
622
- end
623
3
 
624
- def initialize
625
- super(['gem'])
626
- @installed_gems = Set.new
627
- end
4
+ require 'autoproj/package_managers/manager'
5
+ require 'autoproj/package_managers/unknown_os_manager'
6
+ require 'autoproj/package_managers/shell_script_manager'
628
7
 
629
- # Used to override the Gem::SpecFetcher object used by this gem
630
- # manager. Useful mainly for testing
631
- attr_writer :gem_fetcher
632
-
633
- # The set of gems installed during this autoproj session
634
- attr_reader :installed_gems
635
-
636
- def gem_fetcher
637
- if !@gem_fetcher
638
- Autoproj.message " looking for RubyGems updates"
639
- @gem_fetcher = Gem::SpecFetcher.fetcher
640
- end
641
- @gem_fetcher
642
- end
643
-
644
- def guess_gem_program
645
- if Autobuild.programs['gem']
646
- return Autobuild.programs['gem']
647
- end
648
-
649
- ruby_bin = RbConfig::CONFIG['RUBY_INSTALL_NAME']
650
- ruby_bindir = RbConfig::CONFIG['bindir']
651
-
652
- candidates = ['gem']
653
- if ruby_bin =~ /^ruby(.+)$/
654
- candidates << "gem#{$1}"
655
- end
656
-
657
- candidates.each do |gem_name|
658
- if File.file?(gem_full_path = File.join(ruby_bindir, gem_name))
659
- Autobuild.programs['gem'] = gem_full_path
660
- return
661
- end
662
- end
663
-
664
- raise ArgumentError, "cannot find a gem program (tried #{candidates.sort.join(", ")} in #{ruby_bindir})"
665
- end
666
-
667
- def build_gem_cmdlines(gems)
668
- with_version, without_version = gems.partition { |name, v| v }
669
-
670
- cmdlines = []
671
- if !without_version.empty?
672
- cmdlines << without_version.flatten
673
- end
674
- with_version.each do |name, v|
675
- cmdlines << [name, "-v", v]
676
- end
677
- cmdlines
678
- end
679
-
680
- def pristine(gems)
681
- guess_gem_program
682
- base_cmdline = [Autobuild.tool_in_path('ruby'), '-S', Autobuild.tool('gem')]
683
- cmdlines = [
684
- [*base_cmdline, 'clean'],
685
- ]
686
- cmdlines += build_gem_cmdlines(gems).map do |line|
687
- base_cmdline + ["pristine", "--extensions"] + line
688
- end
689
- if gems_interaction(gems, cmdlines)
690
- Autoproj.message " restoring RubyGems: #{gems.map { |g| g.join(" ") }.sort.join(", ")}"
691
- cmdlines.each do |c|
692
- Autobuild::Subprocess.run 'autoproj', 'osdeps', *c
693
- end
694
- end
695
- end
696
-
697
- def install(gems)
698
- guess_gem_program
699
-
700
- base_cmdline = [Autobuild.tool_in_path('ruby'), '-S', Autobuild.tool('gem'), 'install', *GemManager.default_install_options]
701
- if !GemManager.with_doc
702
- base_cmdline << '--no-rdoc' << '--no-ri'
703
- end
704
-
705
- if GemManager.with_prerelease
706
- base_cmdline << "--prerelease"
707
- end
708
-
709
- cmdlines = build_gem_cmdlines(gems).map do |line|
710
- base_cmdline + line
711
- end
712
- if gems_interaction(gems, cmdlines)
713
- Autoproj.message " installing/updating RubyGems dependencies: #{gems.map { |g| g.join(" ") }.sort.join(", ")}"
714
-
715
- cmdlines.each do |c|
716
- Autobuild::Subprocess.run 'autoproj', 'osdeps', *c,
717
- env: Hash['GEM_HOME' => Gem.paths.home,
718
- 'GEM_PATH' => Gem.paths.path.join(":")]
719
- end
720
- gems.each do |name, v|
721
- installed_gems << name
722
- end
723
- true
724
- end
725
- end
726
-
727
- # Returns the set of RubyGem packages in +packages+ that are not already
728
- # installed, or that can be upgraded
729
- def filter_uptodate_packages(gems, options = Hash.new)
730
- options = validate_options options,
731
- install_only: !Autobuild.do_update
732
-
733
- # Don't install gems that are already there ...
734
- gems = gems.dup
735
- gems.delete_if do |name, version|
736
- next(true) if installed_gems.include?(name)
737
-
738
- version_requirements = Gem::Requirement.new(version || '>= 0')
739
- installed =
740
- if Gem::Specification.respond_to?(:find_by_name)
741
- begin
742
- [Gem::Specification.find_by_name(name, version_requirements)]
743
- rescue Gem::LoadError
744
- []
745
- end
746
- else
747
- Gem.source_index.find_name(name, version_requirements)
748
- end
749
-
750
- if !installed.empty? && !options[:install_only]
751
- # Look if we can update the package ...
752
- dep = Gem::Dependency.new(name, version_requirements)
753
- available =
754
- if gem_fetcher.respond_to?(:find_matching)
755
- non_prerelease = gem_fetcher.find_matching(dep, true, true).map(&:first)
756
- if GemManager.with_prerelease
757
- prerelease = gem_fetcher.find_matching(dep, false, true, true).map(&:first)
758
- else prerelease = Array.new
759
- end
760
- (non_prerelease + prerelease).
761
- map { |n, v, _| [n, v] }
762
-
763
- else # Post RubyGems-2.0
764
- type = if GemManager.with_prerelease then :complete
765
- else :released
766
- end
767
-
768
- gem_fetcher.detect(type) do |tuple|
769
- tuple.name == name && dep.match?(tuple)
770
- end.map { |tuple, _| [tuple.name, tuple.version] }
771
- end
772
- installed_version = installed.map(&:version).max
773
- available_version = available.map { |_, v| v }.max
774
- if !available_version
775
- if version
776
- raise ConfigError.new, "cannot find any gem with the name '#{name}' and version #{version}"
777
- else
778
- raise ConfigError.new, "cannot find any gem with the name '#{name}'"
779
- end
780
- end
781
- needs_update = (available_version > installed_version)
782
- !needs_update
783
- else
784
- !installed.empty?
785
- end
786
- end
787
- gems
788
- end
789
-
790
- def parse_package_entry(entry)
791
- if entry =~ /^([^><=~]*)([><=~]+.*)$/
792
- [$1.strip, $2.strip]
793
- else
794
- [entry]
795
- end
796
- end
797
-
798
- def gems_interaction(gems, cmdlines)
799
- if OSDependencies.force_osdeps
800
- return true
801
- elsif enabled?
802
- return true
803
- elsif silent?
804
- return false
805
- end
806
-
807
- # We're not supposed to install rubygem packages but silent is not
808
- # set, so display information about them anyway
809
- puts <<-EOMSG
810
- #{Autoproj.color("The build process and/or the packages require some Ruby Gems to be installed", :bold)}
811
- #{Autoproj.color("and you required autoproj to not do it itself", :bold)}
812
- You can use the --all or --ruby options to autoproj osdeps to install these
813
- packages anyway, and/or change to the osdeps handling mode by running an
814
- autoproj operation with the --reconfigure option as for instance
815
- autoproj build --reconfigure
816
-
817
- The following command line can be used to install them manually
818
-
819
- #{cmdlines.map { |c| c.join(" ") }.join("\n ")}
820
-
821
- Autoproj expects these Gems to be installed in #{GemManager.gem_home} This can
822
- be overridden by setting the AUTOPROJ_GEM_HOME environment variable manually
823
-
824
- EOMSG
825
- print " #{Autoproj.color("Press ENTER to continue ", :bold)}"
826
-
827
- STDOUT.flush
828
- STDIN.readline
829
- puts
830
- false
831
- end
832
- end
833
-
834
- # Using pip to install python packages
835
- class PipManager < Manager
836
-
837
- attr_reader :installed_gems
838
-
839
- def self.initialize_environment(env = Autobuild.env, _manifest = nil, root_dir = Autoproj.root_dir)
840
- env.set 'PYTHONUSERBASE', pip_home(env, root_dir)
841
- end
842
-
843
- # Return the directory where python packages are installed to.
844
- # The actual path is pip_home/lib/pythonx.y/site-packages.
845
- def self.pip_home(env = Autobuild.env, root_dir = Autobuild.root_dir)
846
- env['AUTOPROJ_PYTHONUSERBASE'] || File.join(root_dir,".pip")
847
- end
848
-
849
-
850
- def initialize
851
- super(['pip'])
852
- @installed_pips = Set.new
853
- end
854
-
855
- def guess_pip_program
856
- if Autobuild.programs['pip']
857
- return Autobuild.programs['pip']
858
- end
859
-
860
- Autobuild.programs['pip'] = "pip"
861
- end
862
-
863
- def install(pips)
864
- guess_pip_program
865
- if pips.is_a?(String)
866
- pips = [pips]
867
- end
868
-
869
- base_cmdline = [Autobuild.tool('pip'), 'install','--user']
870
-
871
- cmdlines = [base_cmdline + pips]
872
-
873
- if pips_interaction(pips, cmdlines)
874
- Autoproj.message " installing/updating Python dependencies: "+
875
- "#{pips.sort.join(", ")}"
876
-
877
- cmdlines.each do |c|
878
- Autobuild::Subprocess.run 'autoproj', 'osdeps', *c
879
- end
880
-
881
- pips.each do |p|
882
- @installed_pips << p
883
- end
884
- end
885
- end
886
-
887
- def pips_interaction(pips, cmdlines)
888
- if OSDependencies.force_osdeps
889
- return true
890
- elsif enabled?
891
- return true
892
- elsif silent?
893
- return false
894
- end
895
-
896
- # We're not supposed to install rubygem packages but silent is not
897
- # set, so display information about them anyway
898
- puts <<-EOMSG
899
- #{Autoproj.color("The build process and/or the packages require some Python packages to be installed", :bold)}
900
- #{Autoproj.color("and you required autoproj to not do it itself", :bold)}
901
- The following command line can be used to install them manually
902
-
903
- #{cmdlines.map { |c| c.join(" ") }.join("\n ")}
904
-
905
- Autoproj expects these Python packages to be installed in #{PipManager.pip_home} This can
906
- be overridden by setting the AUTOPROJ_PYTHONUSERBASE environment variable manually
907
-
908
- EOMSG
909
- print " #{Autoproj.color("Press ENTER to continue ", :bold)}"
910
-
911
- STDOUT.flush
912
- STDIN.readline
913
- puts
914
- false
915
- end
916
- end
917
-
918
- end
8
+ require 'autoproj/package_managers/apt_dpkg_manager'
9
+ require 'autoproj/package_managers/emerge_manager'
10
+ require 'autoproj/package_managers/homebrew_manager'
11
+ require 'autoproj/package_managers/pacman_manager'
12
+ require 'autoproj/package_managers/pkg_manager'
13
+ require 'autoproj/package_managers/port_manager'
14
+ require 'autoproj/package_managers/yum_manager'
15
+ require 'autoproj/package_managers/zypper_manager'
919
16
 
17
+ require 'autoproj/package_managers/gem_manager'
18
+ require 'autoproj/package_managers/pip_manager'
920
19
 
20
+ module Autoproj
921
21
  # Manager for packages provided by external package managers
922
22
  class OSDependencies
923
23
  class << self