autoproj 2.12.1 → 2.15.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (133) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/lint.yml +25 -0
  3. data/.github/workflows/test.yml +30 -0
  4. data/.rubocop.yml +79 -91
  5. data/.rubocop_todo.yml +1473 -0
  6. data/Gemfile +9 -9
  7. data/Rakefile +24 -24
  8. data/autoproj.gemspec +24 -22
  9. data/bin/alocate +4 -4
  10. data/bin/alog +6 -7
  11. data/bin/amake +4 -4
  12. data/bin/aup +4 -4
  13. data/bin/autoproj +3 -3
  14. data/bin/autoproj_bootstrap +225 -200
  15. data/bin/autoproj_bootstrap.in +7 -8
  16. data/bin/autoproj_install +224 -199
  17. data/bin/autoproj_install.in +6 -7
  18. data/lib/autoproj/aruba_minitest.rb +6 -11
  19. data/lib/autoproj/autobuild.rb +9 -6
  20. data/lib/autoproj/autobuild_extensions/archive_importer.rb +10 -11
  21. data/lib/autoproj/autobuild_extensions/dsl.rb +66 -36
  22. data/lib/autoproj/autobuild_extensions/git.rb +27 -26
  23. data/lib/autoproj/autobuild_extensions/package.rb +23 -22
  24. data/lib/autoproj/autobuild_extensions/python.rb +18 -0
  25. data/lib/autoproj/autobuild_extensions/svn.rb +1 -2
  26. data/lib/autoproj/base.rb +1 -1
  27. data/lib/autoproj/bash_completion.rb +5 -6
  28. data/lib/autoproj/build_option.rb +22 -24
  29. data/lib/autoproj/cli/base.rb +26 -26
  30. data/lib/autoproj/cli/bootstrap.rb +14 -16
  31. data/lib/autoproj/cli/build.rb +10 -7
  32. data/lib/autoproj/cli/cache.rb +11 -11
  33. data/lib/autoproj/cli/clean.rb +10 -10
  34. data/lib/autoproj/cli/commit.rb +7 -8
  35. data/lib/autoproj/cli/doc.rb +2 -2
  36. data/lib/autoproj/cli/envsh.rb +1 -2
  37. data/lib/autoproj/cli/exec.rb +60 -20
  38. data/lib/autoproj/cli/inspection_tool.rb +13 -7
  39. data/lib/autoproj/cli/locate.rb +30 -41
  40. data/lib/autoproj/cli/log.rb +7 -7
  41. data/lib/autoproj/cli/main.rb +217 -205
  42. data/lib/autoproj/cli/main_doc.rb +22 -21
  43. data/lib/autoproj/cli/main_global.rb +44 -19
  44. data/lib/autoproj/cli/main_plugin.rb +18 -18
  45. data/lib/autoproj/cli/main_test.rb +28 -27
  46. data/lib/autoproj/cli/manifest.rb +7 -7
  47. data/lib/autoproj/cli/osdeps.rb +12 -11
  48. data/lib/autoproj/cli/patcher.rb +2 -3
  49. data/lib/autoproj/cli/query.rb +17 -18
  50. data/lib/autoproj/cli/reconfigure.rb +1 -2
  51. data/lib/autoproj/cli/reset.rb +9 -12
  52. data/lib/autoproj/cli/show.rb +38 -39
  53. data/lib/autoproj/cli/status.rb +56 -44
  54. data/lib/autoproj/cli/switch_config.rb +5 -6
  55. data/lib/autoproj/cli/tag.rb +12 -11
  56. data/lib/autoproj/cli/test.rb +7 -7
  57. data/lib/autoproj/cli/update.rb +97 -43
  58. data/lib/autoproj/cli/utility.rb +14 -12
  59. data/lib/autoproj/cli/version.rb +42 -40
  60. data/lib/autoproj/cli/versions.rb +14 -15
  61. data/lib/autoproj/cli/watch.rb +33 -37
  62. data/lib/autoproj/cli/which.rb +16 -20
  63. data/lib/autoproj/cli.rb +4 -2
  64. data/lib/autoproj/configuration.rb +78 -86
  65. data/lib/autoproj/default.osdeps +29 -3
  66. data/lib/autoproj/environment.rb +42 -23
  67. data/lib/autoproj/exceptions.rb +9 -3
  68. data/lib/autoproj/find_workspace.rb +20 -25
  69. data/lib/autoproj/git_server_configuration.rb +40 -44
  70. data/lib/autoproj/gitorious.rb +1 -1
  71. data/lib/autoproj/installation_manifest.rb +64 -29
  72. data/lib/autoproj/local_package_set.rb +13 -11
  73. data/lib/autoproj/manifest.rb +139 -132
  74. data/lib/autoproj/metapackage.rb +2 -6
  75. data/lib/autoproj/ops/atomic_write.rb +7 -6
  76. data/lib/autoproj/ops/build.rb +4 -6
  77. data/lib/autoproj/ops/cache.rb +41 -43
  78. data/lib/autoproj/ops/cached_env.rb +5 -4
  79. data/lib/autoproj/ops/configuration.rb +519 -507
  80. data/lib/autoproj/ops/import.rb +88 -63
  81. data/lib/autoproj/ops/install.rb +218 -192
  82. data/lib/autoproj/ops/loader.rb +77 -76
  83. data/lib/autoproj/ops/main_config_switcher.rb +36 -45
  84. data/lib/autoproj/ops/phase_reporting.rb +4 -4
  85. data/lib/autoproj/ops/snapshot.rb +250 -247
  86. data/lib/autoproj/ops/tools.rb +76 -78
  87. data/lib/autoproj/ops/watch.rb +6 -6
  88. data/lib/autoproj/ops/which.rb +17 -14
  89. data/lib/autoproj/options.rb +13 -2
  90. data/lib/autoproj/os_package_installer.rb +102 -92
  91. data/lib/autoproj/os_package_query.rb +7 -13
  92. data/lib/autoproj/os_package_resolver.rb +189 -140
  93. data/lib/autoproj/os_repository_installer.rb +4 -4
  94. data/lib/autoproj/os_repository_resolver.rb +8 -6
  95. data/lib/autoproj/package_definition.rb +12 -13
  96. data/lib/autoproj/package_managers/apt_dpkg_manager.rb +19 -11
  97. data/lib/autoproj/package_managers/bundler_manager.rb +186 -129
  98. data/lib/autoproj/package_managers/debian_version.rb +25 -21
  99. data/lib/autoproj/package_managers/emerge_manager.rb +2 -3
  100. data/lib/autoproj/package_managers/gem_manager.rb +68 -77
  101. data/lib/autoproj/package_managers/homebrew_manager.rb +3 -4
  102. data/lib/autoproj/package_managers/manager.rb +8 -3
  103. data/lib/autoproj/package_managers/pacman_manager.rb +2 -3
  104. data/lib/autoproj/package_managers/pip_manager.rb +30 -28
  105. data/lib/autoproj/package_managers/pkg_manager.rb +3 -4
  106. data/lib/autoproj/package_managers/port_manager.rb +2 -3
  107. data/lib/autoproj/package_managers/shell_script_manager.rb +47 -25
  108. data/lib/autoproj/package_managers/unknown_os_manager.rb +5 -8
  109. data/lib/autoproj/package_managers/yum_manager.rb +12 -15
  110. data/lib/autoproj/package_managers/zypper_manager.rb +11 -14
  111. data/lib/autoproj/package_manifest.rb +28 -74
  112. data/lib/autoproj/package_selection.rb +187 -187
  113. data/lib/autoproj/package_set.rb +145 -114
  114. data/lib/autoproj/python.rb +297 -0
  115. data/lib/autoproj/query_base.rb +20 -14
  116. data/lib/autoproj/reporter.rb +19 -19
  117. data/lib/autoproj/repository_managers/apt.rb +102 -68
  118. data/lib/autoproj/repository_managers/unknown_os_manager.rb +3 -3
  119. data/lib/autoproj/ros_condition_parser.rb +84 -0
  120. data/lib/autoproj/ros_package_manifest.rb +125 -0
  121. data/lib/autoproj/shell_completion.rb +16 -13
  122. data/lib/autoproj/source_package_query.rb +29 -36
  123. data/lib/autoproj/system.rb +32 -21
  124. data/lib/autoproj/test.rb +131 -106
  125. data/lib/autoproj/variable_expansion.rb +10 -10
  126. data/lib/autoproj/vcs_definition.rb +53 -37
  127. data/lib/autoproj/version.rb +1 -1
  128. data/lib/autoproj/workspace.rb +143 -108
  129. data/lib/autoproj/zsh_completion.rb +8 -9
  130. data/lib/autoproj.rb +55 -53
  131. data/samples/autoproj/init.rb +1 -2
  132. metadata +86 -65
  133. data/.travis.yml +0 -22
@@ -1,8 +1,8 @@
1
1
  # frozen_string_literal: false
2
2
 
3
- require 'open3'
4
- require 'pathname'
5
- require 'open-uri'
3
+ require "open3"
4
+ require "pathname"
5
+ require "open-uri"
6
6
 
7
7
  module Autoproj
8
8
  module RepositoryManagers
@@ -13,14 +13,14 @@ module Autoproj
13
13
  attr_reader :sources_dir
14
14
  attr_reader :autoproj_sources
15
15
 
16
- SOURCES_DIR = '/etc/apt'.freeze
17
- SOURCE_TYPES = ['deb', 'deb-src'].freeze
18
- AUTOPROJ_SOURCES = '/etc/apt/sources.list.d/autoproj.list'.freeze
16
+ SOURCES_DIR = "/etc/apt".freeze
17
+ SOURCE_TYPES = %w[deb deb-src].freeze
18
+ AUTOPROJ_SOURCES = "/etc/apt/sources.list.d/autoproj.list".freeze
19
19
 
20
20
  def initialize(ws, sources_dir: SOURCES_DIR, autoproj_sources: AUTOPROJ_SOURCES)
21
21
  @sources_dir = sources_dir
22
22
  @autoproj_sources = autoproj_sources
23
- @source_files = Dir[File.join(sources_dir, '**', '*.list')]
23
+ @source_files = Dir[File.join(sources_dir, "**", "*.list")]
24
24
  @source_entries = {}
25
25
 
26
26
  source_files.each { |file| load_sources_from_file(file) }
@@ -28,7 +28,7 @@ module Autoproj
28
28
  end
29
29
 
30
30
  def os_dependencies
31
- super + ['archive-keyring', 'gnupg', 'apt-transport-https']
31
+ super + %w[archive-keyring gnupg apt-transport-https]
32
32
  end
33
33
 
34
34
  def load_sources_from_file(file)
@@ -45,16 +45,16 @@ module Autoproj
45
45
  entry = {}
46
46
  entry[:valid] = false
47
47
  entry[:enabled] = true
48
- entry[:source] = ''
49
- entry[:comment] = ''
48
+ entry[:source] = ""
49
+ entry[:comment] = ""
50
50
 
51
51
  line.strip!
52
- if line.start_with?('#')
52
+ if line.start_with?("#")
53
53
  entry[:enabled] = false
54
54
  line = line[1..-1]
55
55
  end
56
56
 
57
- i = line.index('#')
57
+ i = line.index("#")
58
58
  if i&.positive?
59
59
  entry[:comment] = line[(i + 1)..-1].strip
60
60
  line = line[0..(i - 1)]
@@ -63,7 +63,7 @@ module Autoproj
63
63
  entry[:source] = line.strip
64
64
  chunks = entry[:source].split
65
65
  entry[:valid] = true if SOURCE_TYPES.include?(chunks[0])
66
- entry[:source] = chunks.join(' ')
66
+ entry[:source] = chunks.join(" ")
67
67
 
68
68
  if raise_if_invalid && (!entry[:valid] || !entry[:enabled])
69
69
  raise ConfigError, "Invalid source line: #{entry[:source]}"
@@ -74,7 +74,7 @@ module Autoproj
74
74
 
75
75
  def add_source(source, file = nil)
76
76
  file = if file
77
- File.join(sources_dir, 'sources.list.d', file)
77
+ File.join(sources_dir, "sources.list.d", file)
78
78
  else
79
79
  autoproj_sources
80
80
  end
@@ -95,8 +95,8 @@ module Autoproj
95
95
 
96
96
  def append_entry(contents, entry)
97
97
  unless entry[:enabled]
98
- contents << '#'
99
- contents << ' ' unless entry[:source].start_with?('#')
98
+ contents << "#"
99
+ contents << " " unless entry[:source].start_with?("#")
100
100
  end
101
101
 
102
102
  contents << entry[:source]
@@ -105,17 +105,17 @@ module Autoproj
105
105
  end
106
106
 
107
107
  def enable_entry_in_file(file, enable_entry)
108
- contents = ''
108
+ contents = ""
109
109
  source_entries[file].each do |entry|
110
110
  entry[:enabled] = true if enable_entry[:source] == entry[:source]
111
111
  append_entry(contents, entry)
112
112
  end
113
- run_tee_command(['sudo', 'tee', file], contents)
113
+ run_tee_command(["sudo", "tee", file], contents)
114
114
  true
115
115
  end
116
116
 
117
117
  def add_entry_to_file(file, entry)
118
- run_tee_command(['sudo', 'tee', '-a', file], entry[:source])
118
+ run_tee_command(["sudo", "tee", "-a", file], entry[:source])
119
119
  @source_entries[file] ||= []
120
120
  @source_entries[file] << entry
121
121
  true
@@ -123,7 +123,7 @@ module Autoproj
123
123
 
124
124
  def run_tee_command(command, contents)
125
125
  contents = StringIO.new("#{contents}\n")
126
- Autobuild::Subprocess.run('autoproj', 'osrepos', *command, input_streams: [contents])
126
+ Autobuild::Subprocess.run("autoproj", "osrepos", *command, input_streams: [contents])
127
127
  end
128
128
 
129
129
  def entry_exist?(new_entry)
@@ -140,7 +140,7 @@ module Autoproj
140
140
 
141
141
  def key_exist?(key)
142
142
  exist = false
143
- Open3.popen3({'LANG' => 'C'}, 'apt-key', 'export', key) do |_, _, stderr, wait_thr|
143
+ Open3.popen3({ "LANG" => "C" }, "apt-key", "export", key) do |_, _, stderr, wait_thr|
144
144
  success = wait_thr.value.success?
145
145
  stderr = stderr.read
146
146
  has_error = stderr.match(/WARNING: nothing exported/)
@@ -151,36 +151,36 @@ module Autoproj
151
151
 
152
152
  def apt_update
153
153
  Autobuild::Subprocess.run(
154
- 'autoproj',
155
- 'osrepos',
156
- 'sudo',
157
- 'apt-get',
158
- 'update'
154
+ "autoproj",
155
+ "osrepos",
156
+ "sudo",
157
+ "apt-get",
158
+ "update"
159
159
  )
160
160
  end
161
161
 
162
162
  def add_apt_key(id, origin, type: :keyserver)
163
163
  if type == :keyserver
164
164
  Autobuild::Subprocess.run(
165
- 'autoproj',
166
- 'osrepos',
167
- 'sudo',
168
- 'apt-key',
169
- 'adv',
170
- '--keyserver',
165
+ "autoproj",
166
+ "osrepos",
167
+ "sudo",
168
+ "apt-key",
169
+ "adv",
170
+ "--keyserver",
171
171
  origin,
172
- '--recv-key',
172
+ "--recv-key",
173
173
  id
174
174
  )
175
175
  else
176
- open(origin) do |io|
176
+ URI(origin).open do |io|
177
177
  Autobuild::Subprocess.run(
178
- 'autoproj',
179
- 'osrepos',
180
- 'sudo',
181
- 'apt-key',
182
- 'add',
183
- '-',
178
+ "autoproj",
179
+ "osrepos",
180
+ "sudo",
181
+ "apt-key",
182
+ "add",
183
+ "-",
184
184
  input_streams: [io]
185
185
  )
186
186
  end
@@ -191,24 +191,24 @@ module Autoproj
191
191
 
192
192
  def filter_installed_definitions(definitions)
193
193
  definitions = definitions.dup.reject do |definition|
194
- if definition['type'] == 'repo'
195
- _, entry = source_exist?(definition['repo'])
194
+ if definition["type"] == "repo"
195
+ _, entry = source_exist?(definition["repo"])
196
196
  entry && entry[:enabled]
197
197
  else
198
- key_exist?(definition['id'])
198
+ key_exist?(definition["id"])
199
199
  end
200
200
  end
201
201
  definitions
202
202
  end
203
203
 
204
204
  def print_installing_definitions(definitions)
205
- repos = definitions.select { |definition| definition['type'] == 'repo' }
206
- keys = definitions.select { |definition| definition['type'] == 'key' }
205
+ repos = definitions.select { |definition| definition["type"] == "repo" }
206
+ keys = definitions.select { |definition| definition["type"] == "key" }
207
207
 
208
208
  unless repos.empty?
209
- Autoproj.message ' adding apt repositories:'
209
+ Autoproj.message " adding apt repositories:"
210
210
  repos.each do |repo|
211
- if repo['file']
211
+ if repo["file"]
212
212
  Autoproj.message " #{repo['repo']}, file: #{repo['file']}"
213
213
  else
214
214
  Autoproj.message " #{repo['repo']}"
@@ -217,9 +217,9 @@ module Autoproj
217
217
  end
218
218
  return if keys.empty?
219
219
 
220
- Autoproj.message ' adding apt keys:'
220
+ Autoproj.message " adding apt keys:"
221
221
  keys.each do |key|
222
- if key['keyserver']
222
+ if key["keyserver"]
223
223
  Autoproj.message " id: #{key['id']}, keyserver: #{key['keyserver']}"
224
224
  else
225
225
  Autoproj.message " id: #{key['id']}, url: #{key['url']}"
@@ -249,27 +249,61 @@ module Autoproj
249
249
  # url: 'http://packages.osrfoundation.org/gazebo.key'
250
250
  #
251
251
  def validate_definitions(definitions)
252
- invalid_string = 'Invalid apt repository definition'
253
252
  definitions.each do |definition|
254
- raise ConfigError, "#{invalid_string} type: #{definition['type']}" unless %w[repo key].include?(definition['type'])
255
-
256
- if definition['type'] == 'repo'
257
- raise ConfigError, "#{invalid_string}: 'repo' key missing" if definition['repo'].nil?
258
- raise ConfigError, "#{invalid_string}: 'repo' should be a String" unless definition['repo'].is_a?(String)
259
- raise ConfigError, "#{invalid_string}: 'file' should be a String" if definition['file'] && !definition['file'].is_a?(String)
260
- if definition['file'] && Pathname.new(definition['file']).absolute?
261
- raise ConfigError, "#{invalid_string}: 'file' should be a relative to #{File.join(SOURCES_DIR, 'sources.list.d')}"
262
- end
253
+ case definition["type"]
254
+ when "repo"
255
+ validate_repo_definition(definition)
256
+ when "key"
257
+ validate_key_definition(definition)
263
258
  else
264
- raise ConfigError, "#{invalid_string}: 'id' key missing" if definition['id'].nil?
265
- raise ConfigError, "#{invalid_string}: 'id' should be a String" unless definition['id'].is_a?(String)
266
- raise ConfigError, "#{invalid_string}: 'url' conflicts with 'keyserver'" if definition['url'] && definition['keyserver']
267
- raise ConfigError, "#{invalid_string}: 'url' should be a String" if definition['url'] && !definition['url'].is_a?(String)
268
- raise ConfigError, "#{invalid_string}: 'keyserver' should be a String" if definition['keyserver'] && !definition['keyserver'].is_a?(String)
259
+ raise ConfigError,
260
+ "#{INVALID_REPO_MESSAGE} type: #{definition['type']}"
269
261
  end
270
262
  end
271
263
  end
272
264
 
265
+ INVALID_REPO_MESSAGE = "Invalid apt repository definition".freeze
266
+
267
+ # rubocop:disable Style/GuardClause
268
+
269
+ def validate_repo_definition(definition)
270
+ if definition["repo"].nil?
271
+ raise ConfigError, "#{INVALID_REPO_MESSAGE}: 'repo' key missing"
272
+ elsif !definition["repo"].is_a?(String)
273
+ raise ConfigError,
274
+ "#{INVALID_REPO_MESSAGE}: 'repo' should be a String"
275
+ elsif definition["file"] && !definition["file"].is_a?(String)
276
+ raise ConfigError,
277
+ "#{INVALID_REPO_MESSAGE}: 'file' should be a String"
278
+ elsif definition["file"] && Pathname.new(definition["file"]).absolute?
279
+ raise ConfigError,
280
+ "#{INVALID_REPO_MESSAGE}: 'file' should be relative "\
281
+ "to #{File.join(SOURCES_DIR, 'sources.list.d')}"
282
+ end
283
+
284
+ nil
285
+ end
286
+
287
+ def validate_key_definition(definition)
288
+ if definition["id"].nil?
289
+ raise ConfigError, "#{INVALID_REPO_MESSAGE}: 'id' key missing"
290
+ elsif !definition["id"].is_a?(String)
291
+ raise ConfigError, "#{INVALID_REPO_MESSAGE}: 'id' should be a String"
292
+ elsif definition["url"] && definition["keyserver"]
293
+ raise ConfigError,
294
+ "#{INVALID_REPO_MESSAGE}: 'url' conflicts with 'keyserver'"
295
+ elsif definition["url"] && !definition["url"].is_a?(String)
296
+ raise ConfigError, "#{INVALID_REPO_MESSAGE}: 'url' should be a String"
297
+ elsif definition["keyserver"] && !definition["keyserver"].is_a?(String)
298
+ raise ConfigError,
299
+ "#{INVALID_REPO_MESSAGE}: 'keyserver' should be a String"
300
+ end
301
+
302
+ nil
303
+ end
304
+
305
+ # rubocop:enable Style/GuardClause
306
+
273
307
  def install(definitions)
274
308
  super
275
309
  validate_definitions(definitions)
@@ -277,12 +311,12 @@ module Autoproj
277
311
  print_installing_definitions(definitions)
278
312
 
279
313
  definitions.each do |definition|
280
- if definition['type'] == 'repo'
281
- add_source(definition['repo'], definition['file'])
314
+ if definition["type"] == "repo"
315
+ add_source(definition["repo"], definition["file"])
282
316
  else
283
- type = definition['url'] ? 'url' : 'keyserver'
317
+ type = definition["url"] ? "url" : "keyserver"
284
318
  origin = definition[type]
285
- add_apt_key(definition['id'], origin, type: type.to_sym)
319
+ add_apt_key(definition["id"], origin, type: type.to_sym)
286
320
  end
287
321
  end
288
322
  apt_update unless definitions.empty?
@@ -9,9 +9,9 @@ module Autoproj
9
9
  end
10
10
 
11
11
  def osrepos_interaction_unknown_os
12
- Autoproj.message 'The build process requires some repositories to be added on our operating system', :bold
13
- Autoproj.message 'If they are already added, simply ignore this message', :bold
14
- Autoproj.message 'Press ENTER to continue ', :bold
12
+ Autoproj.message "The build process requires some repositories to be added on our operating system", :bold
13
+ Autoproj.message "If they are already added, simply ignore this message", :bold
14
+ Autoproj.message "Press ENTER to continue ", :bold
15
15
 
16
16
  STDIN.readline
17
17
  nil
@@ -0,0 +1,84 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "parslet"
4
+ require "autoproj/exceptions"
5
+ require "autoproj/variable_expansion"
6
+
7
+ module Autoproj
8
+ # Parses a conditional expression
9
+ # Syntax and rules as defined in https://www.ros.org/reps/rep-0149.html#id20
10
+ class RosConditionParser < Parslet::Parser
11
+ def initialize(context)
12
+ @context = context
13
+ super()
14
+ end
15
+
16
+ def expand(var)
17
+ Autoproj.expand(var, @context)
18
+ rescue StandardError
19
+ ""
20
+ end
21
+
22
+ # Evaluates the Abstract Syntax Tree generated by the parser
23
+ class Transform < Parslet::Transform
24
+ rule(literal: simple(:x)) { String(x) }
25
+ rule(variable: simple(:x)) { expander.call(String(x)) }
26
+ rule(op: simple(:o), lhs: simple(:l), rhs: simple(:r)) { l.send(o, r) }
27
+ rule(op: "and", lhs: simple(:l), rhs: simple(:r)) { l && r }
28
+ rule(op: "or", lhs: simple(:l), rhs: simple(:r)) { l || r }
29
+ end
30
+
31
+ def evaluate(expr)
32
+ Transform.new.apply(parse(expr.strip), expander: method(:expand))
33
+ rescue Parslet::ParseFailed => e
34
+ raise Autoproj::ConfigError, e.message
35
+ end
36
+
37
+ def any_of(strings)
38
+ strings = strings.dup
39
+ strings.reduce(str(strings.shift)) { |acc, s| acc | str(s) }
40
+ end
41
+
42
+ def quoted_literal(quote)
43
+ str(quote) >> (
44
+ str(quote).absent? >> any
45
+ ).repeat.maybe.as(:literal) >> str(quote)
46
+ end
47
+
48
+ def chain(lhs, operator, operation)
49
+ (lhs.as(:lhs) >> operator >> operation.as(:rhs)) | lhs
50
+ end
51
+
52
+ RESERVED = %w[and or].freeze
53
+
54
+ rule(:space) { match['\s\t'].repeat(1) }
55
+ rule(:space?) { space.maybe }
56
+ rule(:lparen) { str("(") >> space? }
57
+ rule(:rparen) { str(")") >> space? }
58
+ rule(:comp_operator) { any_of(%w[== != >= <= > <]).as(:op) >> space? }
59
+ rule(:and_operator) { str("and").as(:op) >> space? }
60
+ rule(:or_operator) { str("or").as(:op) >> space? }
61
+ rule(:literal) do
62
+ (any_of(RESERVED) >> space).absent? >>
63
+ (match('\w') | match["_-"]).repeat(1)
64
+ .as(:literal)
65
+ end
66
+ rule(:double_quote) { quoted_literal('"') }
67
+ rule(:single_quote) { quoted_literal("'") }
68
+ rule(:variable) do
69
+ (
70
+ str("$") >> match('\d').absent? >> (
71
+ match('\w') | match["_"]
72
+ ).repeat(1)
73
+ ).as(:variable)
74
+ end
75
+
76
+ rule(:term) { (literal | single_quote | double_quote | variable) >> space? }
77
+ rule(:primary) { (lparen >> or_operation >> rparen) | term }
78
+ rule(:comp_operation) { chain(primary, comp_operator, comp_operation) }
79
+ rule(:and_operation) { chain(comp_operation, and_operator, and_operation) }
80
+ rule(:or_operation) { chain(and_operation, or_operator, or_operation) }
81
+
82
+ root(:or_operation)
83
+ end
84
+ end
@@ -0,0 +1,125 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Autoproj
4
+ # Access to the information contained in a package's package.xml file
5
+ #
6
+ # Use PackageManifest.load to create
7
+ class RosPackageManifest < PackageManifest
8
+ attr_accessor :name
9
+ attr_writer :build_type
10
+
11
+ def build_type
12
+ @build_type || "catkin"
13
+ end
14
+
15
+ # @api private
16
+ #
17
+ # REXML stream parser object used to load the XML contents into a
18
+ # {PackageManifest} object
19
+ class Loader < PackageManifest::Loader
20
+ MANIFEST_CLASS = RosPackageManifest
21
+ SUPPORTED_MODES = %w[test doc].freeze
22
+ DEPEND_TAGS = %w[depend build_depend build_export_depend
23
+ buildtool_depend buildtool_export_depend
24
+ exec_depend test_depend run_depend doc_depend].to_set.freeze
25
+
26
+ def initialize(path, manifest)
27
+ super
28
+ @env = manifest.package.ws.env
29
+ @condition_parser = RosConditionParser.new(@env)
30
+ end
31
+
32
+ def tag_start(name, attributes)
33
+ super
34
+ exportlevel_tag_start(name, attributes) if @export_level
35
+ end
36
+
37
+ def tag_end(name)
38
+ super
39
+ exportlevel_tag_end(name) if @export_level
40
+ if @tag_level == 0 && name == "package" &&
41
+ (!manifest.name || manifest.name.empty?)
42
+ raise InvalidPackageManifest, "Package name missiing in #{path}"
43
+ end
44
+ end
45
+
46
+ def exportlevel_tag_start(name, attributes)
47
+ return unless name == "build_type"
48
+
49
+ @build_type_condition = attributes["condition"]
50
+ @tag_text = ""
51
+ end
52
+
53
+ def exportlevel_tag_end(name)
54
+ return unless name == "build_type"
55
+ return unless handle_condition(@build_type_condition)
56
+
57
+ manifest.build_type = @tag_text.strip
58
+ end
59
+
60
+ def toplevel_tag_start(name, attributes)
61
+ if DEPEND_TAGS.include?(name)
62
+ @depend_condition = attributes["condition"]
63
+ @tag_text = ""
64
+ elsif TEXT_FIELDS.include?(name)
65
+ @tag_text = ""
66
+ elsif AUTHOR_FIELDS.include?(name)
67
+ @author_email = attributes["email"]
68
+ @tag_text = ""
69
+ elsif name == "name"
70
+ @tag_text = ""
71
+ elsif name == "export"
72
+ @export_level = true
73
+ else
74
+ @tag_text = nil
75
+ end
76
+ end
77
+
78
+ def handle_condition(expr)
79
+ return true unless expr && !expr.empty?
80
+
81
+ @condition_parser.evaluate(expr)
82
+ end
83
+
84
+ def depend_tag_end(name)
85
+ return unless handle_condition(@depend_condition)
86
+
87
+ if @tag_text.strip.empty?
88
+ raise InvalidPackageManifest, "found '#{name}' tag in #{path} "\
89
+ "without content"
90
+ end
91
+
92
+ mode = []
93
+ if (m = /^(\w+)_depend$/.match(name))
94
+ mode = SUPPORTED_MODES & [m[1]]
95
+ end
96
+
97
+ manifest.add_dependency(@tag_text, modes: mode)
98
+ end
99
+
100
+ def author_tag_end(name)
101
+ author_name = @tag_text.strip
102
+ email = @author_email ? @author_email.strip : nil
103
+ email = nil if email&.empty?
104
+ contact = PackageManifest::ContactInfo.new(author_name, email)
105
+ manifest.send("#{name}s").concat([contact])
106
+ end
107
+
108
+ def toplevel_tag_end(name)
109
+ if DEPEND_TAGS.include?(name)
110
+ depend_tag_end(name)
111
+ elsif AUTHOR_FIELDS.include?(name)
112
+ author_tag_end(name)
113
+ elsif TEXT_FIELDS.include?(name)
114
+ field = @tag_text.strip
115
+ manifest.send("#{name}=", field) unless field.empty?
116
+ elsif name == "name"
117
+ manifest.name = @tag_text.strip
118
+ elsif name == "export"
119
+ @export_level = false
120
+ end
121
+ @tag_text = nil
122
+ end
123
+ end
124
+ end
125
+ end
@@ -1,5 +1,5 @@
1
- require 'autoproj/cli/main'
2
- require 'erb'
1
+ require "autoproj/cli/main"
2
+ require "erb"
3
3
 
4
4
  module Autoproj
5
5
  # Generates shell completion for code for a given Thor subclass
@@ -11,14 +11,15 @@ module Autoproj
11
11
  # A hash describing the CLI
12
12
  attr_reader :cli_metadata
13
13
 
14
- TEMPLATES_DIR = File.join(File.dirname(__FILE__), 'templates')
14
+ TEMPLATES_DIR = File.join(File.dirname(__FILE__), "templates")
15
15
 
16
- def initialize(name = 'autoproj', cli: Autoproj::CLI::Main, command: nil)
16
+ def initialize(name = "autoproj", cli: Autoproj::CLI::Main, command: nil)
17
17
  @cli = cli
18
18
  @name = name
19
19
 
20
20
  generate_metadata
21
21
  return unless command
22
+
22
23
  @cli_metadata = subcommand_by_name(*command)
23
24
  @cli_metadata[:name] = "__#{name}"
24
25
  end
@@ -48,8 +49,8 @@ module Autoproj
48
49
  # leaving disabled for now
49
50
  # TODO: log subcommand needs a custom completer,
50
51
  # leaving disabled for now
51
- ['bootstrap', 'envsh', 'reconfigure', 'reset', 'log', 'query',
52
- 'switch-config', %w[global register], %w[global status],
52
+ ["bootstrap", "envsh", "reconfigure", "reset", "log", "query",
53
+ "switch-config", %w[global register], %w[global status],
53
54
  %w[plugin install], %w[plugin remove], %w[plugin list]].each do |command|
54
55
  disable_completion(subcommand_by_name(*command))
55
56
  end
@@ -58,7 +59,7 @@ module Autoproj
58
59
  def generate
59
60
  template_file = File.join(TEMPLATES_DIR, self.class::MAIN_FUNCTION_TEMPLATE)
60
61
  erb = File.read(template_file)
61
- ::ERB.new(erb, nil, '-').result(binding)
62
+ ::ERB.new(erb, nil, "-").result(binding)
62
63
  end
63
64
 
64
65
  def subcommand_by_name(*name, metadata: cli_metadata)
@@ -73,7 +74,7 @@ module Autoproj
73
74
  end
74
75
 
75
76
  def populate_help_subcommands(command_metadata = cli_metadata)
76
- help_subcommand = subcommand_by_name('help',
77
+ help_subcommand = subcommand_by_name("help",
77
78
  metadata: command_metadata)
78
79
 
79
80
  if help_subcommand
@@ -82,9 +83,11 @@ module Autoproj
82
83
  end
83
84
 
84
85
  command_metadata[:subcommands].each do |subcommand|
85
- next if subcommand[:name] == 'help'
86
+ next if subcommand[:name] == "help"
87
+
86
88
  populate_help_subcommands(subcommand)
87
89
  next unless help_subcommand
90
+
88
91
  help_subcommand[:subcommands] << { name: subcommand[:name],
89
92
  aliases: [],
90
93
  description: subcommand[:description],
@@ -98,17 +101,17 @@ module Autoproj
98
101
  source = []
99
102
 
100
103
  prefix = (prefix + [subcommand[:name]])
101
- function_name = prefix.join('_')
104
+ function_name = prefix.join("_")
102
105
  depth = prefix.size + 1
103
106
 
104
107
  template_file = File.join(TEMPLATES_DIR, self.class::SUBCOMMAND_FUNCTION_TEMPLATE)
105
- erb = ::ERB.new(File.read(template_file), nil, '-')
108
+ erb = ::ERB.new(File.read(template_file), nil, "-")
106
109
 
107
110
  source << erb.result(binding)
108
111
  subcommand[:subcommands].each do |subcommand|
109
112
  source << render_subcommand_function(subcommand, prefix: prefix)
110
113
  end
111
- source.join("\n").strip + "\n"
114
+ "#{source.join("\n").strip}\n"
112
115
  end
113
116
 
114
117
  def subcommand_metadata(cli)
@@ -158,7 +161,7 @@ module Autoproj
158
161
  end
159
162
 
160
163
  def hyphenate(s)
161
- s.to_s.tr('_', '-')
164
+ s.to_s.tr("_", "-")
162
165
  end
163
166
  end
164
167
  end