autoproj 2.11.0 → 2.14.0

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 (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)