autoproj 2.11.0 → 2.14.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (52) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +5 -8
  3. data/.travis.yml +5 -3
  4. data/autoproj.gemspec +6 -6
  5. data/bin/alog +1 -0
  6. data/bin/autoproj +1 -1
  7. data/bin/autoproj_bootstrap +130 -67
  8. data/bin/autoproj_bootstrap.in +9 -7
  9. data/bin/autoproj_install +129 -63
  10. data/bin/autoproj_install.in +8 -3
  11. data/lib/autoproj/autobuild_extensions/dsl.rb +27 -12
  12. data/lib/autoproj/base.rb +18 -0
  13. data/lib/autoproj/cli/base.rb +1 -1
  14. data/lib/autoproj/cli/build.rb +8 -3
  15. data/lib/autoproj/cli/cache.rb +79 -7
  16. data/lib/autoproj/cli/inspection_tool.rb +5 -6
  17. data/lib/autoproj/cli/main.rb +33 -9
  18. data/lib/autoproj/cli/show.rb +12 -18
  19. data/lib/autoproj/cli/status.rb +15 -9
  20. data/lib/autoproj/cli/test.rb +1 -1
  21. data/lib/autoproj/cli/update.rb +72 -17
  22. data/lib/autoproj/cli/utility.rb +25 -28
  23. data/lib/autoproj/configuration.rb +15 -4
  24. data/lib/autoproj/default.osdeps +29 -3
  25. data/lib/autoproj/environment.rb +17 -13
  26. data/lib/autoproj/installation_manifest.rb +7 -5
  27. data/lib/autoproj/manifest.rb +14 -6
  28. data/lib/autoproj/ops/build.rb +23 -21
  29. data/lib/autoproj/ops/cache.rb +151 -33
  30. data/lib/autoproj/ops/cached_env.rb +2 -2
  31. data/lib/autoproj/ops/import.rb +23 -4
  32. data/lib/autoproj/ops/install.rb +121 -60
  33. data/lib/autoproj/ops/phase_reporting.rb +49 -0
  34. data/lib/autoproj/ops/snapshot.rb +2 -1
  35. data/lib/autoproj/ops/tools.rb +2 -2
  36. data/lib/autoproj/os_package_installer.rb +19 -11
  37. data/lib/autoproj/package_definition.rb +1 -1
  38. data/lib/autoproj/package_managers/apt_dpkg_manager.rb +49 -28
  39. data/lib/autoproj/package_managers/bundler_manager.rb +102 -19
  40. data/lib/autoproj/package_managers/homebrew_manager.rb +2 -2
  41. data/lib/autoproj/package_managers/pip_manager.rb +34 -22
  42. data/lib/autoproj/package_managers/shell_script_manager.rb +44 -24
  43. data/lib/autoproj/package_manifest.rb +43 -31
  44. data/lib/autoproj/package_set.rb +2 -2
  45. data/lib/autoproj/python.rb +285 -0
  46. data/lib/autoproj/test.rb +26 -10
  47. data/lib/autoproj/variable_expansion.rb +3 -1
  48. data/lib/autoproj/vcs_definition.rb +25 -12
  49. data/lib/autoproj/version.rb +1 -1
  50. data/lib/autoproj/workspace.rb +60 -16
  51. data/lib/autoproj.rb +3 -0
  52. metadata +17 -28
@@ -15,7 +15,7 @@ module Autoproj
15
15
  # somewhere else
16
16
  packages = packages.uniq
17
17
  command_line = "brew info --json=v1 #{packages.join(' ')}"
18
- result = Bundler.with_clean_env do
18
+ result = Autoproj.bundler_with_unbundled_env do
19
19
  (Autobuild::Subprocess.run 'autoproj', 'osdeps', command_line).first
20
20
  end
21
21
 
@@ -30,7 +30,7 @@ module Autoproj
30
30
  end
31
31
  return packages
32
32
  end
33
-
33
+
34
34
  # fall back if something else went wrong
35
35
  if packages.size != result.size
36
36
  Autoproj.warn "brew info returns less or more packages when requested. Falling back to install all packages"
@@ -1,3 +1,5 @@
1
+ require 'autoproj/python'
2
+
1
3
  module Autoproj
2
4
  module PackageManagers
3
5
  # Using pip to install python packages
@@ -25,30 +27,40 @@ module Autoproj
25
27
  end
26
28
 
27
29
  def guess_pip_program
28
- if Autobuild.programs['pip']
29
- return Autobuild.programs['pip']
30
+ unless ws.config.has_value_for?('USE_PYTHON')
31
+ Autoproj::Python.setup_python_configuration_options(ws: ws)
32
+ end
33
+ unless ws.config.get('USE_PYTHON')
34
+ raise ConfigError, "Your current package selection" \
35
+ " requires the use of pip, but" \
36
+ " the use of python is either unspecified or has been denied, see" \
37
+ " setting of USE_PYTHON in your workspace configuration." \
38
+ " Either remove all packages depending on pip packages " \
39
+ " from the workspace layout (manifest) or " \
40
+ " call 'autoproj reconfigure' to change the setting."
41
+
30
42
  end
31
43
 
32
- Autobuild.programs['pip'] = "pip"
44
+ Autobuild.programs['pip'] = "pip" unless Autobuild.programs['pip']
45
+ Autobuild.programs['pip']
33
46
  end
34
47
 
48
+ # rubocop:disable Lint/UnusedMethodArgument
35
49
  def install(pips, filter_uptodate_packages: false, install_only: false)
36
50
  guess_pip_program
37
- if pips.is_a?(String)
38
- pips = [pips]
39
- end
51
+ pips = [pips] if pips.is_a?(String)
40
52
 
41
- base_cmdline = [Autobuild.tool('pip'), 'install','--user']
53
+ base_cmdline = [Autobuild.tool('pip'), 'install', '--user']
42
54
 
43
55
  cmdlines = [base_cmdline + pips]
44
56
 
45
- if pips_interaction(pips, cmdlines)
46
- Autoproj.message " installing/updating Python dependencies: "+
47
- "#{pips.sort.join(", ")}"
57
+ if pips_interaction(cmdlines)
58
+ Autoproj.message " installing/updating Python dependencies:" \
59
+ " #{pips.sort.join(', ')}"
48
60
 
49
61
  cmdlines.each do |c|
50
62
  Autobuild::Subprocess.run 'autoproj', 'osdeps', *c,
51
- env: ws.env.resolved_env
63
+ env: ws.env.resolved_env
52
64
  end
53
65
 
54
66
  pips.each do |p|
@@ -56,8 +68,9 @@ module Autoproj
56
68
  end
57
69
  end
58
70
  end
59
-
60
- def pips_interaction(pips, cmdlines)
71
+ # rubocop:enable Lint/UnusedMethodArgument
72
+
73
+ def pips_interaction(cmdlines)
61
74
  if OSPackageInstaller.force_osdeps
62
75
  return true
63
76
  elsif enabled?
@@ -69,24 +82,23 @@ module Autoproj
69
82
  # We're not supposed to install rubygem packages but silent is not
70
83
  # set, so display information about them anyway
71
84
  puts <<-EOMSG
72
- #{Autoproj.color("The build process and/or the packages require some Python packages to be installed", :bold)}
73
- #{Autoproj.color("and you required autoproj to not do it itself", :bold)}
85
+ #{Autoproj.color('The build process and/or the packages require some Python packages to be installed', :bold)}
86
+ #{Autoproj.color('and you required autoproj to not do it itself', :bold)}
74
87
  The following command line can be used to install them manually
75
-
76
- #{cmdlines.map { |c| c.join(" ") }.join("\n ")}
77
-
88
+ #{' '}
89
+ #{cmdlines.map { |c| c.join(' ') }.join("\n ")}
90
+ #{' '}
78
91
  Autoproj expects these Python packages to be installed in #{pip_home} This can
79
92
  be overridden by setting the AUTOPROJ_PYTHONUSERBASE environment variable manually
80
93
 
81
94
  EOMSG
82
- print " #{Autoproj.color("Press ENTER to continue ", :bold)}"
95
+ print " #{Autoproj.color('Press ENTER to continue ', :bold)}"
83
96
 
84
- STDOUT.flush
85
- STDIN.readline
97
+ $stdout.flush
98
+ $stdin.readline
86
99
  puts
87
100
  false
88
101
  end
89
102
  end
90
103
  end
91
104
  end
92
-
@@ -7,8 +7,10 @@ module Autoproj
7
7
  if with_locking
8
8
  File.open('/tmp/autoproj_osdeps_lock', 'w') do |lock_io|
9
9
  begin
10
- while !lock_io.flock(File::LOCK_EX | File::LOCK_NB)
11
- Autoproj.message " waiting for other autoproj instances to finish their osdeps installation"
10
+ until lock_io.flock(File::LOCK_EX | File::LOCK_NB)
11
+ Autoproj.message " waiting for other autoproj "\
12
+ "instances to finish their osdeps "\
13
+ "installation"
12
14
  sleep 5
13
15
  end
14
16
  return execute(command_line, false, with_root, env: env)
@@ -17,7 +19,7 @@ module Autoproj
17
19
  end
18
20
  end
19
21
  end
20
-
22
+
21
23
  if with_root
22
24
  sudo = Autobuild.tool_in_path('sudo', env: env)
23
25
  command_line = [sudo, *command_line]
@@ -34,10 +36,12 @@ module Autoproj
34
36
  # This declares if this package manager cannot be used concurrently.
35
37
  # If it is the case, autoproj will ensure that there is no two
36
38
  # autoproj instances running this package manager at the same time
37
- #
39
+ #
38
40
  # @return [Boolean]
39
41
  # @see needs_locking=
40
- def needs_locking?; !!@needs_locking end
42
+ def needs_locking?
43
+ @needs_locking
44
+ end
41
45
 
42
46
  # Overrides the {#needs_root?} flag
43
47
  attr_writer :needs_root
@@ -45,10 +49,12 @@ module Autoproj
45
49
  #
46
50
  # This declares if the command line(s) for this package manager
47
51
  # should be started as root. Root access is provided using sudo
48
- #
52
+ #
49
53
  # @return [Boolean]
50
54
  # @see needs_root=
51
- def needs_root?; !!@needs_root end
55
+ def needs_root?
56
+ @needs_root
57
+ end
52
58
 
53
59
  # Command line used by autoproj to install packages
54
60
  #
@@ -83,10 +89,13 @@ module Autoproj
83
89
  # itself, see {#auto_install_cmd}.
84
90
  # @param [Boolean] needs_root if the command lines should be started
85
91
  # as root or not. See {#needs_root?}
86
- def initialize(ws, needs_locking, user_install_cmd, auto_install_cmd,needs_root=true)
92
+ def initialize(ws, needs_locking, user_install_cmd,
93
+ auto_install_cmd, needs_root = true)
87
94
  super(ws)
88
- @needs_locking, @user_install_cmd, @auto_install_cmd,@needs_root =
89
- needs_locking, user_install_cmd, auto_install_cmd, needs_root
95
+ @needs_locking = needs_locking
96
+ @user_install_cmd = user_install_cmd
97
+ @auto_install_cmd = auto_install_cmd
98
+ @needs_root = needs_root
90
99
  end
91
100
 
92
101
  # Generate the shell script that would allow the user to install
@@ -98,7 +107,8 @@ module Autoproj
98
107
  # command-line pattern that should be used to generate the script.
99
108
  # If given, it overrides the default value stored in
100
109
  # {#user_install_cmd]
101
- def generate_user_os_script(os_packages, user_install_cmd: self.user_install_cmd)
110
+ def generate_user_os_script(os_packages,
111
+ user_install_cmd: self.user_install_cmd)
102
112
  if user_install_cmd
103
113
  user_install_cmd.join(" ") + " " + os_packages.join("' '")
104
114
  else generate_auto_os_script(os_packages)
@@ -114,7 +124,8 @@ module Autoproj
114
124
  # command-line pattern that should be used to generate the script.
115
125
  # If given, it overrides the default value stored in
116
126
  # {#auto_install_cmd]
117
- def generate_auto_os_script(os_packages, auto_install_cmd: self.auto_install_cmd)
127
+ def generate_auto_os_script(os_packages,
128
+ auto_install_cmd: self.auto_install_cmd)
118
129
  auto_install_cmd.join(" ") + " " + os_packages.join("' '")
119
130
  end
120
131
 
@@ -139,9 +150,9 @@ module Autoproj
139
150
  # anyway, do so now
140
151
  puts <<-EOMSG
141
152
 
142
- #{Autoproj.color("The build process and/or the packages require some other software to be installed", :bold)}
143
- #{Autoproj.color("and you required autoproj to not install them itself", :bold)}
144
- #{Autoproj.color("\nIf these packages are already installed, simply ignore this message\n", :red) if !respond_to?(:filter_uptodate_packages)}
153
+ #{Autoproj.color('The build process and/or the packages require some other software to be installed', :bold)}
154
+ #{Autoproj.color('and you required autoproj to not install them itself', :bold)}
155
+ #{Autoproj.color('\nIf these packages are already installed, simply ignore this message\n', :red) unless respond_to?(:filter_uptodate_packages)}
145
156
  The following packages are available as OS dependencies, i.e. as prebuilt
146
157
  packages provided by your distribution / operating system. You will have to
147
158
  install them manually if they are not already installed
@@ -152,8 +163,8 @@ module Autoproj
152
163
 
153
164
  #{shell_script.split("\n").join("\n| ")}
154
165
 
155
- EOMSG
156
- print " #{Autoproj.color("Press ENTER to continue ", :bold)}"
166
+ EOMSG
167
+ print " #{Autoproj.color('Press ENTER to continue ', :bold)}"
157
168
  STDOUT.flush
158
169
  STDIN.readline
159
170
  puts
@@ -172,23 +183,33 @@ module Autoproj
172
183
  # packages. See the option in {#generate_auto_os_script}
173
184
  # @return [Boolean] true if packages got installed, false otherwise
174
185
  def install(packages, filter_uptodate_packages: false, install_only: false,
175
- auto_install_cmd: self.auto_install_cmd, user_install_cmd: self.user_install_cmd)
186
+ auto_install_cmd: self.auto_install_cmd,
187
+ user_install_cmd: self.user_install_cmd)
176
188
  return if packages.empty?
177
189
 
178
190
  handled_os = ws.supported_operating_system?
179
191
  if handled_os
180
- shell_script = generate_auto_os_script(packages, auto_install_cmd: auto_install_cmd)
181
- user_shell_script = generate_user_os_script(packages, user_install_cmd: user_install_cmd)
192
+ shell_script = generate_auto_os_script(
193
+ packages, auto_install_cmd: auto_install_cmd
194
+ )
195
+ user_shell_script = generate_user_os_script(
196
+ packages, user_install_cmd: user_install_cmd
197
+ )
182
198
  end
183
199
  if osdeps_interaction(packages, user_shell_script)
184
- Autoproj.message " installing OS packages: #{packages.sort.join(", ")}"
200
+ Autoproj.message " installing OS packages: "\
201
+ "#{packages.sort.join(', ')}"
185
202
 
186
203
  if Autoproj.verbose
187
- Autoproj.message "Generating installation script for non-ruby OS dependencies"
204
+ Autoproj.message "Generating installation script for "\
205
+ "non-ruby OS dependencies"
188
206
  Autoproj.message shell_script
189
207
  end
190
208
 
191
- ShellScriptManager.execute([*auto_install_cmd, *packages], needs_locking?, needs_root?, env: ws.env)
209
+ ShellScriptManager.execute(
210
+ [*auto_install_cmd, *packages], needs_locking?,
211
+ needs_root?, env: ws.env
212
+ )
192
213
  return true
193
214
  end
194
215
  false
@@ -196,4 +217,3 @@ module Autoproj
196
217
  end
197
218
  end
198
219
  end
199
-
@@ -30,13 +30,15 @@ module Autoproj
30
30
  # @param [Boolean] ros_manifest whether the file follows the ROS format
31
31
  # @return [PackageManifest]
32
32
  # @see load
33
- def self.parse(package, contents, path: '<loaded from string>', loader_class: Loader)
33
+ def self.parse(package, contents,
34
+ path: '<loaded from string>', loader_class: Loader)
34
35
  manifest = PackageManifest.new(package, path)
35
36
  loader = loader_class.new(path, manifest)
36
37
  begin
37
38
  REXML::Document.parse_stream(contents, loader)
38
39
  rescue REXML::ParseException => e
39
- raise Autobuild::PackageException.new(package.name, 'prepare'), "invalid #{file}: #{e.message}"
40
+ raise Autobuild::PackageException.new(package.name, 'prepare'),
41
+ "invalid #{file}: #{e.message}"
40
42
  end
41
43
  manifest
42
44
  end
@@ -45,7 +47,7 @@ module Autoproj
45
47
  Dependency = Struct.new :name, :optional, :modes
46
48
 
47
49
  # The Autobuild::Package instance this manifest applies on
48
- attr_reader :package
50
+ attr_accessor :package
49
51
  attr_reader :path
50
52
  attr_accessor :description
51
53
  attr_accessor :brief_description
@@ -64,7 +66,7 @@ module Autoproj
64
66
  end
65
67
 
66
68
  def has_documentation?
67
- !!description
69
+ description
68
70
  end
69
71
 
70
72
  def documentation
@@ -72,7 +74,7 @@ module Autoproj
72
74
  end
73
75
 
74
76
  def has_short_documentation?
75
- !!brief_description
77
+ brief_description
76
78
  end
77
79
 
78
80
  def short_documentation
@@ -95,11 +97,12 @@ module Autoproj
95
97
  # Whether this is a null manifest (used for packages that have actually
96
98
  # no manifest) or not
97
99
  def null?
98
- !!@null
100
+ @null
99
101
  end
100
102
 
101
- def each_dependency(in_modes = Array.new, &block)
102
- return enum_for(__method__, in_modes) if !block_given?
103
+ def each_dependency(in_modes = [])
104
+ return enum_for(__method__, in_modes) unless block_given?
105
+
103
106
  dependencies.each do |dep|
104
107
  if dep.modes.empty? || in_modes.any? { |m| dep.modes.include?(m) }
105
108
  yield(dep.name, dep.optional)
@@ -108,24 +111,28 @@ module Autoproj
108
111
  end
109
112
 
110
113
  def each_os_dependency(modes = Array.new, &block)
111
- Autoproj.warn_deprecated "#{self.class}##{__method__}", "call #each_dependency instead"
112
- return each_dependency(modes, &block)
114
+ Autoproj.warn_deprecated "#{self.class}##{__method__}",
115
+ "call #each_dependency instead"
116
+ each_dependency(modes, &block)
113
117
  end
114
118
 
115
119
  def each_package_dependency(modes = Array.new, &block)
116
- Autoproj.warn_deprecated "#{self.class}##{__method__}", "call #each_dependency instead"
117
- return each_dependency(modes, &block)
120
+ Autoproj.warn_deprecated "#{self.class}##{__method__}",
121
+ "call #each_dependency instead"
122
+ each_dependency(modes, &block)
118
123
  end
119
124
 
120
125
  def each_rock_maintainer
121
- return enum_for(__method__) if !block_given?
126
+ return enum_for(__method__) unless block_given?
127
+
122
128
  rock_maintainers.each do |m|
123
129
  yield(m.name, m.email)
124
130
  end
125
131
  end
126
132
 
127
133
  def each_maintainer
128
- return enum_for(__method__) if !block_given?
134
+ return enum_for(__method__) unless block_given?
135
+
129
136
  maintainers.each do |m|
130
137
  yield(m.name, m.email)
131
138
  end
@@ -134,7 +141,8 @@ module Autoproj
134
141
  # Enumerates the name and email of each author. If no email is present,
135
142
  # yields (name, nil)
136
143
  def each_author
137
- return enum_for(__method__) if !block_given?
144
+ return enum_for(__method__) unless block_given?
145
+
138
146
  authors.each do |m|
139
147
  yield(m.name, m.email)
140
148
  end
@@ -178,11 +186,13 @@ module Autoproj
178
186
 
179
187
  def parse_depend_tag(tag_name, attributes, modes: [], optional: false)
180
188
  package = attributes['package'] || attributes['name']
181
- if !package
182
- raise InvalidPackageManifest, "found '#{tag_name}' tag in #{path} without a 'package' attribute"
189
+ unless package
190
+ raise InvalidPackageManifest,
191
+ "found '#{tag_name}' tag in #{path} "\
192
+ "without a 'package' attribute"
183
193
  end
184
194
 
185
- if tag_modes = attributes['modes']
195
+ if (tag_modes = attributes['modes'])
186
196
  modes += tag_modes.split(',')
187
197
  end
188
198
 
@@ -195,7 +205,7 @@ module Autoproj
195
205
  def parse_contact_field(text)
196
206
  text.strip.split(',').map do |str|
197
207
  name, email = str.split('/').map(&:strip)
198
- email = nil if email && email.empty?
208
+ email = nil if email&.empty?
199
209
  ContactInfo.new(name, email)
200
210
  end
201
211
  end
@@ -213,7 +223,7 @@ module Autoproj
213
223
  elsif name =~ /^(\w+)_depend$/
214
224
  parse_depend_tag(name, attributes, modes: [$1])
215
225
  elsif name == 'description'
216
- if brief = attributes['brief']
226
+ if (brief = attributes['brief'])
217
227
  manifest.brief_description = brief
218
228
  end
219
229
  @tag_text = ''
@@ -225,14 +235,13 @@ module Autoproj
225
235
  @tag_text = nil
226
236
  end
227
237
  end
238
+
228
239
  def toplevel_tag_end(name)
229
240
  if AUTHOR_FIELDS.include?(name)
230
241
  manifest.send("#{name}s").concat(parse_contact_field(@tag_text))
231
242
  elsif TEXT_FIELDS.include?(name)
232
243
  field = @tag_text.strip
233
- if !field.empty?
234
- manifest.send("#{name}=", field)
235
- end
244
+ manifest.send("#{name}=", field) unless field.empty?
236
245
  elsif name == 'tags'
237
246
  manifest.tags.concat(@tag_text.strip.split(',').map(&:strip))
238
247
  end
@@ -245,10 +254,10 @@ module Autoproj
245
254
  # REXML stream parser object used to load the XML contents into a
246
255
  # {PackageManifest} object
247
256
  class RosLoader < Loader
248
- SUPPORTED_MODES = ['test', 'doc'].freeze
249
- DEPEND_TAGS = Set['depend', 'build_depend', 'build_export_depend',
250
- 'buildtool_depend', 'buildtool_export_depend',
251
- 'exec_depend', 'test_depend', 'run_depend', 'doc_depend']
257
+ SUPPORTED_MODES = %w[test doc].freeze
258
+ DEPEND_TAGS = %w[depend build_depend build_export_depend
259
+ buildtool_depend buildtool_export_depend
260
+ exec_depend test_depend run_depend doc_depend].to_set.freeze
252
261
 
253
262
  def toplevel_tag_start(name, attributes)
254
263
  if DEPEND_TAGS.include?(name)
@@ -265,18 +274,21 @@ module Autoproj
265
274
 
266
275
  def toplevel_tag_end(name)
267
276
  if DEPEND_TAGS.include?(name)
268
- raise InvalidPackageManifest, "found '#{name}' tag in #{path} without content" if @tag_text.strip.empty?
277
+ if @tag_text.strip.empty?
278
+ raise InvalidPackageManifest, "found '#{name}' tag in #{path} "\
279
+ "without content"
280
+ end
269
281
 
270
282
  mode = []
271
- if name =~ /^(\w+)_depend$/
272
- mode = SUPPORTED_MODES & [$1]
283
+ if (m = /^(\w+)_depend$/.match(name))
284
+ mode = SUPPORTED_MODES & [m[1]]
273
285
  end
274
286
 
275
287
  manifest.add_dependency(@tag_text, modes: mode)
276
288
  elsif AUTHOR_FIELDS.include?(name)
277
289
  author_name = @tag_text.strip
278
290
  email = @author_email ? @author_email.strip : nil
279
- email = nil if email && email.empty?
291
+ email = nil if email&.empty?
280
292
  contact = ContactInfo.new(author_name, email)
281
293
  manifest.send("#{name}s").concat([contact])
282
294
  elsif TEXT_FIELDS.include?(name)