autoproj 2.0.0.b7 → 2.0.0.rc1

Sign up to get free protection for your applications and to get access to all the features.
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
@@ -0,0 +1,70 @@
1
+ module Autoproj
2
+ module PackageManagers
3
+ # Package manager interface for systems that use APT and dpkg for
4
+ # package management
5
+ class AptDpkgManager < ShellScriptManager
6
+ attr_accessor :status_file
7
+
8
+ def initialize(status_file = "/var/lib/dpkg/status")
9
+ @status_file = status_file
10
+ super(['apt-dpkg'], true,
11
+ "apt-get install '%s'",
12
+ "export DEBIAN_FRONTEND=noninteractive; apt-get install -y '%s'")
13
+ end
14
+
15
+ # On a dpkg-enabled system, checks if the provided package is installed
16
+ # and returns true if it is the case
17
+ def installed?(package_name)
18
+ if !@installed_packages
19
+ @installed_packages = Set.new
20
+ dpkg_status = File.readlines(status_file)
21
+ dpkg_status << ""
22
+
23
+ current_packages = []
24
+ is_installed = false
25
+ dpkg_status.each do |line|
26
+ line = line.chomp
27
+ line = line.encode( "UTF-8", "binary", :invalid => :replace, :undef => :replace)
28
+ if line == ""
29
+ if is_installed
30
+ current_packages.each do |pkg|
31
+ @installed_packages << pkg
32
+ end
33
+ is_installed = false
34
+ end
35
+ current_packages.clear
36
+ elsif line =~ /Package: (.*)$/
37
+ current_packages << $1
38
+ elsif line =~ /Provides: (.*)$/
39
+ current_packages.concat($1.split(',').map(&:strip))
40
+ elsif line == "Status: install ok installed"
41
+ is_installed = true
42
+ end
43
+ end
44
+ end
45
+
46
+ if package_name =~ /^(\w[a-z0-9+-.]+)/
47
+ @installed_packages.include?($1)
48
+ else
49
+ Autoproj.warn "#{package_name} is not a valid Debian package name"
50
+ false
51
+ end
52
+ end
53
+
54
+ def install(packages)
55
+ if super
56
+ # Invalidate caching of installed packages, as we just
57
+ # installed new packages !
58
+ @installed_packages = nil
59
+ end
60
+ end
61
+
62
+ def filter_uptodate_packages(packages, options = Hash.new)
63
+ packages.find_all do |package_name|
64
+ !installed?(package_name)
65
+ end
66
+ end
67
+ end
68
+ end
69
+ end
70
+
@@ -0,0 +1,14 @@
1
+ module Autoproj
2
+ module PackageManagers
3
+ # Package manager interface for systems that use emerge (i.e. gentoo) as
4
+ # their package manager
5
+ class EmergeManager < ShellScriptManager
6
+ def initialize
7
+ super(['emerge'], true,
8
+ "emerge '%s'",
9
+ "emerge --noreplace '%s'")
10
+ end
11
+ end
12
+ end
13
+ end
14
+
@@ -0,0 +1,313 @@
1
+ module Autoproj
2
+ module PackageManagers
3
+ # Package manager interface for the RubyGems system
4
+ class GemManager < Manager
5
+ class << self
6
+ attr_writer :with_prerelease
7
+ attr_accessor :with_doc
8
+ end
9
+ @with_prerelease = false
10
+ @with_doc = false
11
+
12
+ def self.with_prerelease(*value)
13
+ if value.empty?
14
+ @with_prerelease
15
+ else
16
+ begin
17
+ saved_flag = @with_prerelease
18
+ @with_prerelease = value.first
19
+ yield
20
+ ensure
21
+ @with_prerelease = saved_flag
22
+ end
23
+ end
24
+ end
25
+
26
+ # Filters all paths that come from other autoproj installations out
27
+ # of GEM_PATH
28
+ def self.initialize_environment(env = Autobuild.env, manifest = Autoproj.manifest, root_dir = Autoproj.root_dir)
29
+ env.original_env['GEM_PATH'] =
30
+ (env['GEM_PATH'] || "").split(File::PATH_SEPARATOR).find_all do |p|
31
+ !Autoproj.in_autoproj_installation?(p)
32
+ end.join(File::PATH_SEPARATOR)
33
+ env.inherit 'GEM_PATH'
34
+ env.init_from_env 'GEM_PATH'
35
+
36
+ orig_gem_path = env.original_env['GEM_PATH'].split(File::PATH_SEPARATOR)
37
+ env.system_env['GEM_PATH'] = Gem.default_path
38
+ env.original_env['GEM_PATH'] = orig_gem_path.join(File::PATH_SEPARATOR)
39
+
40
+ manifest.each_reused_autoproj_installation do |p|
41
+ p_gems = File.join(p, '.gems')
42
+ if File.directory?(p_gems)
43
+ env.push_path 'GEM_PATH', p_gems
44
+ env.push_path 'PATH', File.join(p_gems, 'bin')
45
+ end
46
+ end
47
+
48
+ @gem_home = (ENV['AUTOPROJ_GEM_HOME'] || File.join(root_dir, ".gems"))
49
+ env.push_path 'GEM_PATH', gem_home
50
+ env.set 'GEM_HOME', gem_home
51
+ env.push_path 'PATH', "#{gem_home}/bin"
52
+
53
+ # Now, reset the directories in our own RubyGems instance
54
+ Gem.paths = env.resolved_env
55
+
56
+ use_cache_dir
57
+ end
58
+
59
+ # Override the gem home detected by {initialize_environment}, or set
60
+ # it in cases where calling {initialize_environment} is not possible
61
+ def self.gem_home=(gem_home)
62
+ @gem_home = gem_home
63
+ end
64
+
65
+ # A global cache directory that should be used to avoid
66
+ # re-downloading gems
67
+ def self.cache_dir
68
+ if dir = ENV['AUTOBUILD_CACHE_DIR']
69
+ dir = File.join(dir, 'gems')
70
+ FileUtils.mkdir_p dir
71
+ dir
72
+ end
73
+ end
74
+
75
+ def self.use_cache_dir
76
+ # If there is a cache directory, make sure .gems/cache points to
77
+ # it (there are no programmatic ways to override this)
78
+ if cache = cache_dir
79
+ gem_cache_dir = File.join(gem_home, 'cache')
80
+ if !File.symlink?(gem_cache_dir) || File.readlink(gem_cache_dir) != cache
81
+ FileUtils.mkdir_p gem_home
82
+ FileUtils.rm_rf gem_cache_dir
83
+ Autoproj.create_symlink(cache, gem_cache_dir)
84
+ end
85
+ end
86
+ end
87
+
88
+ # Return the directory in which RubyGems package should be installed
89
+ def self.gem_home
90
+ @gem_home
91
+ end
92
+
93
+ # Returns the set of default options that are added to gem
94
+ #
95
+ # By default, we add --no-user-install to un-break distributions
96
+ # like Arch that set --user-install by default (thus disabling the
97
+ # role of GEM_HOME)
98
+ def self.default_install_options
99
+ @default_install_options ||= ['--no-user-install', '--no-format-executable']
100
+ end
101
+
102
+ def initialize
103
+ super(['gem'])
104
+ @installed_gems = Set.new
105
+ end
106
+
107
+ # Used to override the Gem::SpecFetcher object used by this gem
108
+ # manager. Useful mainly for testing
109
+ attr_writer :gem_fetcher
110
+
111
+ # The set of gems installed during this autoproj session
112
+ attr_reader :installed_gems
113
+
114
+ def gem_fetcher
115
+ if !@gem_fetcher
116
+ Autoproj.message " looking for RubyGems updates"
117
+ @gem_fetcher = Gem::SpecFetcher.fetcher
118
+ end
119
+ @gem_fetcher
120
+ end
121
+
122
+ def guess_gem_program
123
+ if Autobuild.programs['gem']
124
+ return Autobuild.programs['gem']
125
+ end
126
+
127
+ ruby_bin = RbConfig::CONFIG['RUBY_INSTALL_NAME']
128
+ ruby_bindir = RbConfig::CONFIG['bindir']
129
+
130
+ candidates = ['gem']
131
+ if ruby_bin =~ /^ruby(.+)$/
132
+ candidates << "gem#{$1}"
133
+ end
134
+
135
+ candidates.each do |gem_name|
136
+ if File.file?(gem_full_path = File.join(ruby_bindir, gem_name))
137
+ Autobuild.programs['gem'] = gem_full_path
138
+ return
139
+ end
140
+ end
141
+
142
+ raise ArgumentError, "cannot find a gem program (tried #{candidates.sort.join(", ")} in #{ruby_bindir})"
143
+ end
144
+
145
+ def build_gem_cmdlines(gems)
146
+ with_version, without_version = gems.partition { |name, v| v }
147
+
148
+ cmdlines = []
149
+ if !without_version.empty?
150
+ cmdlines << without_version.flatten
151
+ end
152
+ with_version.each do |name, v|
153
+ cmdlines << [name, "-v", v]
154
+ end
155
+ cmdlines
156
+ end
157
+
158
+ def pristine(gems)
159
+ guess_gem_program
160
+ base_cmdline = [Autobuild.tool_in_path('ruby'), '-S', Autobuild.tool('gem')]
161
+ cmdlines = [
162
+ [*base_cmdline, 'clean'],
163
+ ]
164
+ cmdlines += build_gem_cmdlines(gems).map do |line|
165
+ base_cmdline + ["pristine", "--extensions"] + line
166
+ end
167
+ if gems_interaction(gems, cmdlines)
168
+ Autoproj.message " restoring RubyGems: #{gems.map { |g| g.join(" ") }.sort.join(", ")}"
169
+ cmdlines.each do |c|
170
+ Autobuild::Subprocess.run 'autoproj', 'osdeps', *c
171
+ end
172
+ end
173
+ end
174
+
175
+ def install(gems)
176
+ guess_gem_program
177
+
178
+ base_cmdline = [Autobuild.tool_in_path('ruby'), '-S', Autobuild.tool('gem'), 'install', *GemManager.default_install_options]
179
+ if !GemManager.with_doc
180
+ base_cmdline << '--no-rdoc' << '--no-ri'
181
+ end
182
+
183
+ if GemManager.with_prerelease
184
+ base_cmdline << "--prerelease"
185
+ end
186
+
187
+ cmdlines = build_gem_cmdlines(gems).map do |line|
188
+ base_cmdline + line
189
+ end
190
+ if gems_interaction(gems, cmdlines)
191
+ Autoproj.message " installing/updating RubyGems dependencies: #{gems.map { |g| g.join(" ") }.sort.join(", ")}"
192
+
193
+ cmdlines.each do |c|
194
+ Autobuild::Subprocess.run 'autoproj', 'osdeps', *c,
195
+ env: Hash['GEM_HOME' => Gem.paths.home,
196
+ 'GEM_PATH' => Gem.paths.path.join(":")]
197
+ end
198
+ gems.each do |name, v|
199
+ installed_gems << name
200
+ end
201
+ true
202
+ end
203
+ end
204
+
205
+ # Returns the set of RubyGem packages in +packages+ that are not already
206
+ # installed, or that can be upgraded
207
+ def filter_uptodate_packages(gems, options = Hash.new)
208
+ options = validate_options options,
209
+ install_only: !Autobuild.do_update
210
+
211
+ # Don't install gems that are already there ...
212
+ gems = gems.dup
213
+ gems.delete_if do |name, version|
214
+ next(true) if installed_gems.include?(name)
215
+
216
+ version_requirements = Gem::Requirement.new(version || '>= 0')
217
+ installed =
218
+ if Gem::Specification.respond_to?(:find_by_name)
219
+ begin
220
+ [Gem::Specification.find_by_name(name, version_requirements)]
221
+ rescue Gem::LoadError
222
+ []
223
+ end
224
+ else
225
+ Gem.source_index.find_name(name, version_requirements)
226
+ end
227
+
228
+ if !installed.empty? && !options[:install_only]
229
+ # Look if we can update the package ...
230
+ dep = Gem::Dependency.new(name, version_requirements)
231
+ available =
232
+ if gem_fetcher.respond_to?(:find_matching)
233
+ non_prerelease = gem_fetcher.find_matching(dep, true, true).map(&:first)
234
+ if GemManager.with_prerelease
235
+ prerelease = gem_fetcher.find_matching(dep, false, true, true).map(&:first)
236
+ else prerelease = Array.new
237
+ end
238
+ (non_prerelease + prerelease).
239
+ map { |n, v, _| [n, v] }
240
+
241
+ else # Post RubyGems-2.0
242
+ type = if GemManager.with_prerelease then :complete
243
+ else :released
244
+ end
245
+
246
+ gem_fetcher.detect(type) do |tuple|
247
+ tuple.name == name && dep.match?(tuple)
248
+ end.map { |tuple, _| [tuple.name, tuple.version] }
249
+ end
250
+ installed_version = installed.map(&:version).max
251
+ available_version = available.map { |_, v| v }.max
252
+ if !available_version
253
+ if version
254
+ raise ConfigError.new, "cannot find any gem with the name '#{name}' and version #{version}"
255
+ else
256
+ raise ConfigError.new, "cannot find any gem with the name '#{name}'"
257
+ end
258
+ end
259
+ needs_update = (available_version > installed_version)
260
+ !needs_update
261
+ else
262
+ !installed.empty?
263
+ end
264
+ end
265
+ gems
266
+ end
267
+
268
+ def parse_package_entry(entry)
269
+ if entry =~ /^([^><=~]*)([><=~]+.*)$/
270
+ [$1.strip, $2.strip]
271
+ else
272
+ [entry]
273
+ end
274
+ end
275
+
276
+ def gems_interaction(gems, cmdlines)
277
+ if OSDependencies.force_osdeps
278
+ return true
279
+ elsif enabled?
280
+ return true
281
+ elsif silent?
282
+ return false
283
+ end
284
+
285
+ # We're not supposed to install rubygem packages but silent is not
286
+ # set, so display information about them anyway
287
+ puts <<-EOMSG
288
+ #{Autoproj.color("The build process and/or the packages require some Ruby Gems to be installed", :bold)}
289
+ #{Autoproj.color("and you required autoproj to not do it itself", :bold)}
290
+ You can use the --all or --ruby options to autoproj osdeps to install these
291
+ packages anyway, and/or change to the osdeps handling mode by running an
292
+ autoproj operation with the --reconfigure option as for instance
293
+ autoproj build --reconfigure
294
+
295
+ The following command line can be used to install them manually
296
+
297
+ #{cmdlines.map { |c| c.join(" ") }.join("\n ")}
298
+
299
+ Autoproj expects these Gems to be installed in #{GemManager.gem_home} This can
300
+ be overridden by setting the AUTOPROJ_GEM_HOME environment variable manually
301
+
302
+ EOMSG
303
+ print " #{Autoproj.color("Press ENTER to continue ", :bold)}"
304
+
305
+ STDOUT.flush
306
+ STDIN.readline
307
+ puts
308
+ false
309
+ end
310
+ end
311
+ end
312
+ end
313
+
@@ -0,0 +1,44 @@
1
+ module Autoproj
2
+ module PackageManagers
3
+ # Package manager interface for Mac OS using homebrew as
4
+ # its package manager
5
+ class HomebrewManager < ShellScriptManager
6
+ def initialize
7
+ super(['brew'], true,
8
+ "brew install '%s'",
9
+ "brew install '%s'",
10
+ false)
11
+ end
12
+
13
+ def filter_uptodate_packages(packages, options = Hash.new)
14
+ # TODO there might be duplicates in packages which should be fixed
15
+ # somewhere else
16
+ packages = packages.uniq
17
+ result = `brew info --json=v1 '#{packages.join("' '")}'`
18
+ result = begin
19
+ JSON.parse(result)
20
+ rescue JSON::ParserError
21
+ if result && !result.empty?
22
+ Autoproj.warn "Error while parsing result of brew info --json=v1"
23
+ else
24
+ # one of the packages is unknown fallback to install all
25
+ # packaes which will complain about it
26
+ end
27
+ return packages
28
+ end
29
+ # fall back if something else went wrong
30
+ if packages.size != result.size
31
+ Autoproj.warn "brew info returns less or more packages when requested. Falling back to install all packages"
32
+ return packages
33
+ end
34
+
35
+ new_packages = []
36
+ result.each do |pkg|
37
+ new_packages << pkg["name"] if pkg["installed"].empty?
38
+ end
39
+ new_packages
40
+ end
41
+ end
42
+ end
43
+ end
44
+
@@ -0,0 +1,45 @@
1
+ module Autoproj
2
+ module PackageManagers
3
+ # Base class for all package managers. Subclasses must add the
4
+ # #install(packages) method and may add the
5
+ # #filter_uptodate_packages(packages) method
6
+ #
7
+ # Package managers must be registered in PACKAGE_HANDLERS and
8
+ # (if applicable) OS_PACKAGE_HANDLERS.
9
+ class Manager
10
+ # @return [Array<String>] the various names this package manager is
11
+ # known about
12
+ attr_reader :names
13
+
14
+ attr_writer :enabled
15
+ def enabled?; !!@enabled end
16
+
17
+ attr_writer :silent
18
+ def silent?; !!@silent end
19
+
20
+ # Create a package manager registered with various names
21
+ #
22
+ # @param [Array<String>] names the package manager names. It MUST be
23
+ # different from the OS names that autoproj uses. See the comment
24
+ # for OS_PACKAGE_HANDLERS for an explanation
25
+ def initialize(names = [])
26
+ @names = names.dup
27
+ @enabled = true
28
+ @silent = true
29
+ end
30
+
31
+ # The primary name for this package manager
32
+ def name
33
+ names.first
34
+ end
35
+
36
+ # Overload to perform initialization of environment variables in
37
+ # order to have a properly functioning package manager
38
+ #
39
+ # This is e.g. needed for python pip or rubygems
40
+ def self.initialize_environment(_env = nil, _manifest = nil, _root_dir = Autoproj.root_dir)
41
+ end
42
+ end
43
+ end
44
+ end
45
+