autoproj 2.13.0 → 2.15.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.github/workflows/lint.yml +25 -0
- data/.github/workflows/test.yml +30 -0
- data/.rubocop.yml +79 -91
- data/.rubocop_todo.yml +1473 -0
- data/Gemfile +9 -9
- data/Rakefile +24 -24
- data/autoproj.gemspec +24 -22
- data/bin/alocate +4 -4
- data/bin/alog +5 -7
- data/bin/amake +4 -4
- data/bin/aup +4 -4
- data/bin/autoproj +3 -3
- data/bin/autoproj_bootstrap +224 -199
- data/bin/autoproj_bootstrap.in +7 -8
- data/bin/autoproj_install +223 -198
- data/bin/autoproj_install.in +6 -7
- data/lib/autoproj/aruba_minitest.rb +6 -11
- data/lib/autoproj/autobuild.rb +9 -6
- data/lib/autoproj/autobuild_extensions/archive_importer.rb +10 -11
- data/lib/autoproj/autobuild_extensions/dsl.rb +64 -34
- data/lib/autoproj/autobuild_extensions/git.rb +27 -26
- data/lib/autoproj/autobuild_extensions/package.rb +23 -22
- data/lib/autoproj/autobuild_extensions/python.rb +18 -0
- data/lib/autoproj/autobuild_extensions/svn.rb +1 -2
- data/lib/autoproj/base.rb +1 -1
- data/lib/autoproj/bash_completion.rb +5 -6
- data/lib/autoproj/build_option.rb +22 -24
- data/lib/autoproj/cli/base.rb +26 -26
- data/lib/autoproj/cli/bootstrap.rb +14 -16
- data/lib/autoproj/cli/build.rb +10 -7
- data/lib/autoproj/cli/cache.rb +11 -11
- data/lib/autoproj/cli/clean.rb +10 -10
- data/lib/autoproj/cli/commit.rb +7 -8
- data/lib/autoproj/cli/doc.rb +2 -2
- data/lib/autoproj/cli/envsh.rb +1 -2
- data/lib/autoproj/cli/exec.rb +60 -20
- data/lib/autoproj/cli/inspection_tool.rb +13 -7
- data/lib/autoproj/cli/locate.rb +30 -41
- data/lib/autoproj/cli/log.rb +7 -7
- data/lib/autoproj/cli/main.rb +213 -204
- data/lib/autoproj/cli/main_doc.rb +22 -21
- data/lib/autoproj/cli/main_global.rb +44 -19
- data/lib/autoproj/cli/main_plugin.rb +18 -18
- data/lib/autoproj/cli/main_test.rb +28 -27
- data/lib/autoproj/cli/manifest.rb +7 -7
- data/lib/autoproj/cli/osdeps.rb +12 -11
- data/lib/autoproj/cli/patcher.rb +2 -3
- data/lib/autoproj/cli/query.rb +17 -18
- data/lib/autoproj/cli/reconfigure.rb +1 -2
- data/lib/autoproj/cli/reset.rb +9 -12
- data/lib/autoproj/cli/show.rb +38 -39
- data/lib/autoproj/cli/status.rb +45 -39
- data/lib/autoproj/cli/switch_config.rb +5 -6
- data/lib/autoproj/cli/tag.rb +12 -11
- data/lib/autoproj/cli/test.rb +7 -7
- data/lib/autoproj/cli/update.rb +35 -37
- data/lib/autoproj/cli/utility.rb +11 -10
- data/lib/autoproj/cli/version.rb +42 -40
- data/lib/autoproj/cli/versions.rb +14 -15
- data/lib/autoproj/cli/watch.rb +33 -37
- data/lib/autoproj/cli/which.rb +16 -20
- data/lib/autoproj/cli.rb +4 -2
- data/lib/autoproj/configuration.rb +77 -85
- data/lib/autoproj/default.osdeps +18 -3
- data/lib/autoproj/environment.rb +42 -23
- data/lib/autoproj/exceptions.rb +9 -3
- data/lib/autoproj/find_workspace.rb +20 -25
- data/lib/autoproj/git_server_configuration.rb +40 -44
- data/lib/autoproj/gitorious.rb +1 -1
- data/lib/autoproj/installation_manifest.rb +64 -29
- data/lib/autoproj/local_package_set.rb +13 -11
- data/lib/autoproj/manifest.rb +137 -130
- data/lib/autoproj/metapackage.rb +2 -6
- data/lib/autoproj/ops/atomic_write.rb +7 -6
- data/lib/autoproj/ops/build.rb +4 -6
- data/lib/autoproj/ops/cache.rb +41 -43
- data/lib/autoproj/ops/cached_env.rb +5 -4
- data/lib/autoproj/ops/configuration.rb +525 -507
- data/lib/autoproj/ops/import.rb +76 -64
- data/lib/autoproj/ops/install.rb +217 -191
- data/lib/autoproj/ops/loader.rb +77 -76
- data/lib/autoproj/ops/main_config_switcher.rb +36 -45
- data/lib/autoproj/ops/phase_reporting.rb +4 -4
- data/lib/autoproj/ops/snapshot.rb +250 -247
- data/lib/autoproj/ops/tools.rb +76 -78
- data/lib/autoproj/ops/watch.rb +6 -6
- data/lib/autoproj/ops/which.rb +17 -14
- data/lib/autoproj/options.rb +13 -2
- data/lib/autoproj/os_package_installer.rb +102 -92
- data/lib/autoproj/os_package_query.rb +7 -13
- data/lib/autoproj/os_package_resolver.rb +189 -140
- data/lib/autoproj/os_repository_installer.rb +4 -4
- data/lib/autoproj/os_repository_resolver.rb +8 -6
- data/lib/autoproj/package_definition.rb +12 -13
- data/lib/autoproj/package_managers/apt_dpkg_manager.rb +19 -11
- data/lib/autoproj/package_managers/bundler_manager.rb +186 -129
- data/lib/autoproj/package_managers/debian_version.rb +25 -21
- data/lib/autoproj/package_managers/emerge_manager.rb +2 -3
- data/lib/autoproj/package_managers/gem_manager.rb +68 -77
- data/lib/autoproj/package_managers/homebrew_manager.rb +3 -4
- data/lib/autoproj/package_managers/manager.rb +8 -3
- data/lib/autoproj/package_managers/pacman_manager.rb +2 -3
- data/lib/autoproj/package_managers/pip_manager.rb +30 -28
- data/lib/autoproj/package_managers/pkg_manager.rb +3 -4
- data/lib/autoproj/package_managers/port_manager.rb +2 -3
- data/lib/autoproj/package_managers/shell_script_manager.rb +47 -25
- data/lib/autoproj/package_managers/unknown_os_manager.rb +5 -8
- data/lib/autoproj/package_managers/yum_manager.rb +12 -15
- data/lib/autoproj/package_managers/zypper_manager.rb +11 -14
- data/lib/autoproj/package_manifest.rb +28 -74
- data/lib/autoproj/package_selection.rb +187 -187
- data/lib/autoproj/package_set.rb +144 -113
- data/lib/autoproj/python.rb +297 -0
- data/lib/autoproj/query_base.rb +20 -14
- data/lib/autoproj/reporter.rb +19 -19
- data/lib/autoproj/repository_managers/apt.rb +102 -68
- data/lib/autoproj/repository_managers/unknown_os_manager.rb +3 -3
- data/lib/autoproj/ros_condition_parser.rb +84 -0
- data/lib/autoproj/ros_package_manifest.rb +125 -0
- data/lib/autoproj/shell_completion.rb +16 -13
- data/lib/autoproj/source_package_query.rb +29 -36
- data/lib/autoproj/system.rb +32 -21
- data/lib/autoproj/test.rb +127 -104
- data/lib/autoproj/variable_expansion.rb +7 -9
- data/lib/autoproj/vcs_definition.rb +35 -32
- data/lib/autoproj/version.rb +1 -1
- data/lib/autoproj/workspace.rb +142 -108
- data/lib/autoproj/zsh_completion.rb +8 -9
- data/lib/autoproj.rb +55 -55
- data/samples/autoproj/init.rb +1 -2
- metadata +80 -46
- data/.travis.yml +0 -24
@@ -1,8 +1,8 @@
|
|
1
1
|
# frozen_string_literal: false
|
2
2
|
|
3
|
-
require
|
4
|
-
require
|
5
|
-
require
|
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 =
|
17
|
-
SOURCE_TYPES = [
|
18
|
-
AUTOPROJ_SOURCES =
|
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,
|
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 + [
|
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,
|
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 <<
|
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([
|
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([
|
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(
|
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({
|
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
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
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
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
165
|
+
"autoproj",
|
166
|
+
"osrepos",
|
167
|
+
"sudo",
|
168
|
+
"apt-key",
|
169
|
+
"adv",
|
170
|
+
"--keyserver",
|
171
171
|
origin,
|
172
|
-
|
172
|
+
"--recv-key",
|
173
173
|
id
|
174
174
|
)
|
175
175
|
else
|
176
|
-
|
176
|
+
URI(origin).open do |io|
|
177
177
|
Autobuild::Subprocess.run(
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
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[
|
195
|
-
_, entry = source_exist?(definition[
|
194
|
+
if definition["type"] == "repo"
|
195
|
+
_, entry = source_exist?(definition["repo"])
|
196
196
|
entry && entry[:enabled]
|
197
197
|
else
|
198
|
-
key_exist?(definition[
|
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[
|
206
|
-
keys = definitions.select { |definition| definition[
|
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
|
209
|
+
Autoproj.message " adding apt repositories:"
|
210
210
|
repos.each do |repo|
|
211
|
-
if repo[
|
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
|
220
|
+
Autoproj.message " adding apt keys:"
|
221
221
|
keys.each do |key|
|
222
|
-
if key[
|
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
|
-
|
255
|
-
|
256
|
-
|
257
|
-
|
258
|
-
|
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,
|
265
|
-
|
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[
|
281
|
-
add_source(definition[
|
314
|
+
if definition["type"] == "repo"
|
315
|
+
add_source(definition["repo"], definition["file"])
|
282
316
|
else
|
283
|
-
type = definition[
|
317
|
+
type = definition["url"] ? "url" : "keyserver"
|
284
318
|
origin = definition[type]
|
285
|
-
add_apt_key(definition[
|
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
|
13
|
-
Autoproj.message
|
14
|
-
Autoproj.message
|
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
|
2
|
-
require
|
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__),
|
14
|
+
TEMPLATES_DIR = File.join(File.dirname(__FILE__), "templates")
|
15
15
|
|
16
|
-
def initialize(name =
|
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
|
-
[
|
52
|
-
|
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,
|
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(
|
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] ==
|
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
|
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
|