autoproj 2.15.0 → 2.15.1
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.
- checksums.yaml +4 -4
- data/autoproj.gemspec +2 -0
- data/bin/autoproj_bootstrap +44 -22
- data/bin/autoproj_install +44 -22
- data/lib/autoproj/autobuild.rb +4 -0
- data/lib/autoproj/autobuild_extensions/dsl.rb +26 -0
- data/lib/autoproj/autobuild_extensions/python.rb +18 -0
- data/lib/autoproj/configuration.rb +2 -3
- data/lib/autoproj/ops/configuration.rb +55 -48
- data/lib/autoproj/ops/import.rb +3 -1
- data/lib/autoproj/ops/install.rb +44 -22
- data/lib/autoproj/package_managers/apt_dpkg_manager.rb +9 -1
- data/lib/autoproj/package_managers/bundler_manager.rb +37 -17
- data/lib/autoproj/package_managers/pip_manager.rb +6 -14
- data/lib/autoproj/package_managers/shell_script_manager.rb +19 -7
- data/lib/autoproj/package_manifest.rb +5 -52
- data/lib/autoproj/package_set.rb +17 -0
- data/lib/autoproj/python.rb +26 -14
- data/lib/autoproj/repository_managers/apt.rb +1 -1
- data/lib/autoproj/ros_condition_parser.rb +84 -0
- data/lib/autoproj/ros_package_manifest.rb +125 -0
- data/lib/autoproj/version.rb +1 -1
- data/lib/autoproj.rb +2 -0
- metadata +34 -3
@@ -370,7 +370,7 @@ module Autoproj
|
|
370
370
|
end
|
371
371
|
|
372
372
|
# Parse the contents of a gemfile into a set of
|
373
|
-
def merge_gemfiles(*path, unlock: [])
|
373
|
+
def merge_gemfiles(*path, ruby_version: nil, unlock: [])
|
374
374
|
gems_remotes = Set.new
|
375
375
|
dependencies = Hash.new do |h, k|
|
376
376
|
h[k] = Hash.new do |i, j|
|
@@ -410,6 +410,9 @@ module Autoproj
|
|
410
410
|
g = g[0..-2] if g.end_with?("/")
|
411
411
|
contents << "source '#{g}'"
|
412
412
|
end
|
413
|
+
if ruby_version
|
414
|
+
contents << "ruby \"#{ruby_version}\" if respond_to?(:ruby)"
|
415
|
+
end
|
413
416
|
valid_keys = %w[group groups git path glob name branch ref tag
|
414
417
|
require submodules platform platforms type
|
415
418
|
source install_if]
|
@@ -526,34 +529,32 @@ module Autoproj
|
|
526
529
|
end
|
527
530
|
end
|
528
531
|
|
529
|
-
gemfiles =
|
530
|
-
gemfiles << File.join(ws.dot_autoproj_dir, "Gemfile")
|
531
|
-
|
532
|
-
# Save the osdeps entries in a temporary gemfile and finally
|
533
|
-
# merge the whole lot of it
|
534
|
-
gemfile_contents = Tempfile.open "autoproj-gemfile" do |io|
|
535
|
-
gems.map { |entry| GemEntry.parse(entry) }
|
536
|
-
.sort_by(&:name)
|
537
|
-
.each { |entry| io.puts entry.to_gemfile_line }
|
532
|
+
gemfiles = []
|
538
533
|
|
539
|
-
|
540
|
-
|
541
|
-
|
542
|
-
# want to mess it up
|
543
|
-
merge_gemfiles(*gemfiles)
|
534
|
+
unless gems.empty?
|
535
|
+
osdeps_gemfile_io = prepare_osdeps_gemfile(gems)
|
536
|
+
gemfiles << osdeps_gemfile_io.path
|
544
537
|
end
|
545
538
|
|
539
|
+
gemfiles += workspace_configuration_gemfiles
|
540
|
+
# The autoproj gemfile needs to be last, we really don't
|
541
|
+
# want to mess it up
|
542
|
+
gemfiles << File.join(ws.dot_autoproj_dir, "Gemfile")
|
543
|
+
|
544
|
+
ruby_version = RUBY_VERSION.gsub(/\.\d+$/, ".0")
|
545
|
+
gemfile_contents =
|
546
|
+
merge_gemfiles(*gemfiles, ruby_version: "~> #{ruby_version}")
|
547
|
+
|
546
548
|
FileUtils.mkdir_p root_dir
|
547
549
|
updated = (!File.exist?(gemfile_path) ||
|
548
550
|
File.read(gemfile_path) != gemfile_contents)
|
549
551
|
if updated
|
550
552
|
Ops.atomic_write(gemfile_path) do |io|
|
551
|
-
io.puts "ruby \"#{RUBY_VERSION}\" if respond_to?(:ruby)"
|
552
553
|
io.puts gemfile_contents
|
553
554
|
end
|
554
555
|
end
|
555
556
|
|
556
|
-
options =
|
557
|
+
options = []
|
557
558
|
binstubs_path = File.join(root_dir, "bin")
|
558
559
|
if updated || !install_only || !File.file?("#{gemfile_path}.lock")
|
559
560
|
self.class.run_bundler_install(ws, gemfile_path, *options,
|
@@ -580,6 +581,25 @@ module Autoproj
|
|
580
581
|
backup_clean(backups)
|
581
582
|
end
|
582
583
|
|
584
|
+
# Prepare a Gemfile that contains osdeps gem declarations
|
585
|
+
#
|
586
|
+
# @param [Array<String,Hash>] gems osdeps declarations as understood
|
587
|
+
# by {GemEntry.parse}
|
588
|
+
# @return [File]
|
589
|
+
def prepare_osdeps_gemfile(gems)
|
590
|
+
io = Tempfile.open "autoproj-gemfile"
|
591
|
+
io.puts "source \"https://rubygems.org\""
|
592
|
+
gems.map { |entry| GemEntry.parse(entry) }
|
593
|
+
.sort_by(&:name)
|
594
|
+
.each { |entry| io.puts entry.to_gemfile_line }
|
595
|
+
|
596
|
+
io.flush
|
597
|
+
io
|
598
|
+
rescue Exception
|
599
|
+
io&.close
|
600
|
+
raise
|
601
|
+
end
|
602
|
+
|
583
603
|
def discover_rubylib
|
584
604
|
require "bundler"
|
585
605
|
Tempfile.open "autoproj-rubylib" do |io|
|
@@ -27,24 +27,16 @@ module Autoproj
|
|
27
27
|
end
|
28
28
|
|
29
29
|
def guess_pip_program
|
30
|
-
|
31
|
-
Autoproj::Python.setup_python_configuration_options(ws: ws)
|
32
|
-
end
|
33
|
-
unless ws.config.get("USE_PYTHON")
|
34
|
-
raise ConfigError,
|
35
|
-
"Your current package selection requires the use of pip, but" \
|
36
|
-
" the use of python is either unspecified or has been denied,"\
|
37
|
-
" see 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
|
-
|
42
|
-
end
|
43
|
-
|
30
|
+
activate_python
|
44
31
|
Autobuild.programs["pip"] = "pip" unless Autobuild.programs["pip"]
|
45
32
|
Autobuild.programs["pip"]
|
46
33
|
end
|
47
34
|
|
35
|
+
def activate_python
|
36
|
+
Autoproj::Python.setup_python_configuration_options(ws: ws)
|
37
|
+
Autoproj::Python.assert_python_activated(ws: ws)
|
38
|
+
end
|
39
|
+
|
48
40
|
def install(pips, filter_uptodate_packages: false, install_only: false)
|
49
41
|
guess_pip_program
|
50
42
|
pips = [pips] if pips.is_a?(String)
|
@@ -3,7 +3,8 @@ module Autoproj
|
|
3
3
|
# Base class for all package managers that simply require the call of a
|
4
4
|
# shell script to install packages (e.g. yum, apt, ...)
|
5
5
|
class ShellScriptManager < Manager
|
6
|
-
def self.execute(command_line, with_locking, with_root,
|
6
|
+
def self.execute(command_line, with_locking, with_root,
|
7
|
+
env: Autoproj.workspace.env, inherit: Set.new)
|
7
8
|
if with_locking
|
8
9
|
File.open("/tmp/autoproj_osdeps_lock", "w") do |lock_io|
|
9
10
|
until lock_io.flock(File::LOCK_EX | File::LOCK_NB)
|
@@ -12,18 +13,28 @@ module Autoproj
|
|
12
13
|
"installation"
|
13
14
|
sleep 5
|
14
15
|
end
|
15
|
-
return execute(command_line, false, with_root,
|
16
|
+
return execute(command_line, false, with_root,
|
17
|
+
env: env, inherit: inherit)
|
16
18
|
ensure
|
17
19
|
lock_io.flock(File::LOCK_UN)
|
18
20
|
end
|
19
21
|
end
|
20
22
|
|
23
|
+
process_env = env
|
21
24
|
if with_root
|
22
|
-
|
23
|
-
|
25
|
+
process_env = Autobuild::Environment.new
|
26
|
+
process_env.isolate
|
27
|
+
process_env.add_path("PATH", "/usr/local/sbin",
|
28
|
+
"/usr/sbin", "/sbin")
|
29
|
+
|
30
|
+
inherit.each { |var| process_env.set(var, env[var]) }
|
31
|
+
sudo = Autobuild.tool_in_path("sudo", env: process_env)
|
32
|
+
command_line = [sudo, "--preserve-env", *command_line]
|
24
33
|
end
|
25
34
|
|
26
|
-
Autobuild::Subprocess.run "autoproj", "osdeps", *command_line
|
35
|
+
Autobuild::Subprocess.run "autoproj", "osdeps", *command_line,
|
36
|
+
env: process_env.resolved_env,
|
37
|
+
env_inherit: false
|
27
38
|
end
|
28
39
|
|
29
40
|
# Overrides the {#needs_locking?} flag
|
@@ -194,7 +205,8 @@ module Autoproj
|
|
194
205
|
# @return [Boolean] true if packages got installed, false otherwise
|
195
206
|
def install(packages, filter_uptodate_packages: false, install_only: false,
|
196
207
|
auto_install_cmd: self.auto_install_cmd,
|
197
|
-
user_install_cmd: self.user_install_cmd
|
208
|
+
user_install_cmd: self.user_install_cmd,
|
209
|
+
inherit: Set.new)
|
198
210
|
return if packages.empty?
|
199
211
|
|
200
212
|
handled_os = ws.supported_operating_system?
|
@@ -218,7 +230,7 @@ module Autoproj
|
|
218
230
|
|
219
231
|
ShellScriptManager.execute(
|
220
232
|
[*auto_install_cmd, *packages], needs_locking?,
|
221
|
-
needs_root?, env: ws.env
|
233
|
+
needs_root?, env: ws.env, inherit: inherit
|
222
234
|
)
|
223
235
|
return true
|
224
236
|
end
|
@@ -17,7 +17,7 @@ module Autoproj
|
|
17
17
|
# @return [PackageManifest]
|
18
18
|
# @see parse
|
19
19
|
def self.load(package, file, ros_manifest: false)
|
20
|
-
loader_class = ros_manifest ?
|
20
|
+
loader_class = ros_manifest ? RosPackageManifest::Loader : Loader
|
21
21
|
parse(package, File.read(file), path: file, loader_class: loader_class)
|
22
22
|
end
|
23
23
|
|
@@ -32,7 +32,7 @@ module Autoproj
|
|
32
32
|
# @see load
|
33
33
|
def self.parse(package, contents,
|
34
34
|
path: "<loaded from string>", loader_class: Loader)
|
35
|
-
manifest =
|
35
|
+
manifest = loader_class::MANIFEST_CLASS.new(package, path)
|
36
36
|
loader = loader_class.new(path, manifest)
|
37
37
|
begin
|
38
38
|
REXML::Document.parse_stream(contents, loader)
|
@@ -167,6 +167,7 @@ module Autoproj
|
|
167
167
|
end
|
168
168
|
|
169
169
|
def text(text)
|
170
|
+
@tag_text = @tag_text.dup
|
170
171
|
@tag_text << text if @tag_text
|
171
172
|
end
|
172
173
|
end
|
@@ -178,6 +179,8 @@ module Autoproj
|
|
178
179
|
class Loader < BaseLoader
|
179
180
|
attr_reader :path, :manifest
|
180
181
|
|
182
|
+
MANIFEST_CLASS = PackageManifest
|
183
|
+
|
181
184
|
def initialize(path, manifest)
|
182
185
|
super()
|
183
186
|
@path = path
|
@@ -249,55 +252,5 @@ module Autoproj
|
|
249
252
|
@tag_text = nil
|
250
253
|
end
|
251
254
|
end
|
252
|
-
|
253
|
-
# @api private
|
254
|
-
#
|
255
|
-
# REXML stream parser object used to load the XML contents into a
|
256
|
-
# {PackageManifest} object
|
257
|
-
class RosLoader < Loader
|
258
|
-
SUPPORTED_MODES = %w[test doc].freeze
|
259
|
-
DEPEND_TAGS = %w[depend build_depend build_export_depend
|
260
|
-
buildtool_depend buildtool_export_depend
|
261
|
-
exec_depend test_depend run_depend doc_depend].to_set.freeze
|
262
|
-
|
263
|
-
def toplevel_tag_start(name, attributes)
|
264
|
-
if DEPEND_TAGS.include?(name)
|
265
|
-
@tag_text = ""
|
266
|
-
elsif TEXT_FIELDS.include?(name)
|
267
|
-
@tag_text = ""
|
268
|
-
elsif AUTHOR_FIELDS.include?(name)
|
269
|
-
@author_email = attributes["email"]
|
270
|
-
@tag_text = ""
|
271
|
-
else
|
272
|
-
@tag_text = nil
|
273
|
-
end
|
274
|
-
end
|
275
|
-
|
276
|
-
def toplevel_tag_end(name)
|
277
|
-
if DEPEND_TAGS.include?(name)
|
278
|
-
if @tag_text.strip.empty?
|
279
|
-
raise InvalidPackageManifest, "found '#{name}' tag in #{path} "\
|
280
|
-
"without content"
|
281
|
-
end
|
282
|
-
|
283
|
-
mode = []
|
284
|
-
if (m = /^(\w+)_depend$/.match(name))
|
285
|
-
mode = SUPPORTED_MODES & [m[1]]
|
286
|
-
end
|
287
|
-
|
288
|
-
manifest.add_dependency(@tag_text, modes: mode)
|
289
|
-
elsif AUTHOR_FIELDS.include?(name)
|
290
|
-
author_name = @tag_text.strip
|
291
|
-
email = @author_email ? @author_email.strip : nil
|
292
|
-
email = nil if email&.empty?
|
293
|
-
contact = ContactInfo.new(author_name, email)
|
294
|
-
manifest.send("#{name}s").concat([contact])
|
295
|
-
elsif TEXT_FIELDS.include?(name)
|
296
|
-
field = @tag_text.strip
|
297
|
-
manifest.send("#{name}=", field) unless field.empty?
|
298
|
-
end
|
299
|
-
@tag_text = nil
|
300
|
-
end
|
301
|
-
end
|
302
255
|
end
|
303
256
|
end
|
data/lib/autoproj/package_set.rb
CHANGED
@@ -793,6 +793,23 @@ module Autoproj
|
|
793
793
|
vcs
|
794
794
|
end
|
795
795
|
|
796
|
+
# Recursively resolve imports for a given package set
|
797
|
+
def self.resolve_imports(pkg_set, parents = Set.new)
|
798
|
+
return Set.new if pkg_set.imports.empty?
|
799
|
+
|
800
|
+
updated_parents = parents | [pkg_set]
|
801
|
+
|
802
|
+
imports = pkg_set.imports.dup
|
803
|
+
pkg_set.imports.each do |p|
|
804
|
+
if parents.include?(p)
|
805
|
+
raise "Cycling dependency between package sets encountered:" \
|
806
|
+
"#{p.name} <--> #{pkg_set.name}"
|
807
|
+
end
|
808
|
+
imports.merge(resolve_imports(p, updated_parents))
|
809
|
+
end
|
810
|
+
imports
|
811
|
+
end
|
812
|
+
|
796
813
|
# Enumerates the Autobuild::Package instances that are defined in this
|
797
814
|
# source
|
798
815
|
def each_package
|
data/lib/autoproj/python.rb
CHANGED
@@ -168,18 +168,18 @@ module Autoproj
|
|
168
168
|
end
|
169
169
|
end
|
170
170
|
|
171
|
-
def self.remove_python_shims(
|
172
|
-
shim_path = File.join(
|
171
|
+
def self.remove_python_shims(prefix_dir)
|
172
|
+
shim_path = File.join(prefix_dir, "bin", "python")
|
173
173
|
FileUtils.rm shim_path if File.exist?(shim_path)
|
174
174
|
end
|
175
175
|
|
176
|
-
def self.remove_pip_shims(
|
177
|
-
shim_path = File.join(
|
176
|
+
def self.remove_pip_shims(prefix_dir)
|
177
|
+
shim_path = File.join(prefix_dir, "bin", "pip")
|
178
178
|
FileUtils.rm shim_path if File.exist?(shim_path)
|
179
179
|
end
|
180
180
|
|
181
|
-
def self.rewrite_python_shims(python_executable,
|
182
|
-
shim_path = File.join(
|
181
|
+
def self.rewrite_python_shims(python_executable, prefix_dir)
|
182
|
+
shim_path = File.join(prefix_dir, "bin")
|
183
183
|
unless File.exist?(shim_path)
|
184
184
|
FileUtils.mkdir_p shim_path
|
185
185
|
Autoproj.warn "Autoproj::Python.rewrite_python_shims: creating "\
|
@@ -196,8 +196,8 @@ module Autoproj
|
|
196
196
|
python_path
|
197
197
|
end
|
198
198
|
|
199
|
-
def self.rewrite_pip_shims(python_executable,
|
200
|
-
shim_path = File.join(
|
199
|
+
def self.rewrite_pip_shims(python_executable, prefix_dir)
|
200
|
+
shim_path = File.join(prefix_dir, "bin")
|
201
201
|
unless File.exist?(shim_path)
|
202
202
|
FileUtils.mkdir_p shim_path
|
203
203
|
Autoproj.warn "Autoproj::Python.rewrite_pip_shims: creating "\
|
@@ -224,14 +224,14 @@ module Autoproj
|
|
224
224
|
|
225
225
|
ws.osdep_suffixes << "python#{$1}" if version =~ /^([0-9]+)\./
|
226
226
|
|
227
|
-
rewrite_python_shims(bin, ws.
|
228
|
-
rewrite_pip_shims(bin, ws.
|
227
|
+
rewrite_python_shims(bin, ws.dot_autoproj_dir)
|
228
|
+
rewrite_pip_shims(bin, ws.dot_autoproj_dir)
|
229
229
|
[bin, version]
|
230
230
|
end
|
231
231
|
|
232
232
|
def self.deactivate_python(ws: Autoproj.workspace)
|
233
|
-
remove_python_shims(ws.
|
234
|
-
remove_pip_shims(ws.
|
233
|
+
remove_python_shims(ws.dot_autoproj_dir)
|
234
|
+
remove_pip_shims(ws.dot_autoproj_dir)
|
235
235
|
ws.config.reset("python_executable")
|
236
236
|
ws.config.reset("python_version")
|
237
237
|
end
|
@@ -260,6 +260,18 @@ module Autoproj
|
|
260
260
|
[bin, version, path]
|
261
261
|
end
|
262
262
|
|
263
|
+
def self.assert_python_activated(ws: Autoproj.workspace)
|
264
|
+
return true if ws.config.get("USE_PYTHON")
|
265
|
+
|
266
|
+
raise ConfigError,
|
267
|
+
"Your current package selection requires the use of python," \
|
268
|
+
" but this is either unspecified or has been denied,"\
|
269
|
+
" see setting of USE_PYTHON in your workspace configuration." \
|
270
|
+
" Either remove all packages depending on pip packages " \
|
271
|
+
" from the workspace layout (manifest) or " \
|
272
|
+
" call 'autoproj reconfigure' to change the setting."
|
273
|
+
end
|
274
|
+
|
263
275
|
def self.setup_python_configuration_options(ws: Autoproj.workspace)
|
264
276
|
ws.config.declare "USE_PYTHON", "boolean",
|
265
277
|
default: "no",
|
@@ -267,8 +279,8 @@ module Autoproj
|
|
267
279
|
|
268
280
|
if ws.config.get("USE_PYTHON")
|
269
281
|
unless ws.config.has_value_for?("python_executable")
|
270
|
-
remove_python_shims(ws.
|
271
|
-
remove_pip_shims(ws.
|
282
|
+
remove_python_shims(ws.dot_autoproj_dir)
|
283
|
+
remove_pip_shims(ws.dot_autoproj_dir)
|
272
284
|
python_bin, = auto_resolve_python(ws: ws)
|
273
285
|
end
|
274
286
|
|
@@ -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
|
data/lib/autoproj/version.rb
CHANGED
data/lib/autoproj.rb
CHANGED
@@ -27,7 +27,9 @@ require "autoproj/package_definition"
|
|
27
27
|
require "autoproj/package_selection"
|
28
28
|
require "autoproj/metapackage"
|
29
29
|
require "autoproj/manifest"
|
30
|
+
require "autoproj/ros_condition_parser"
|
30
31
|
require "autoproj/package_manifest"
|
32
|
+
require "autoproj/ros_package_manifest"
|
31
33
|
require "autoproj/installation_manifest"
|
32
34
|
require "autoproj/os_package_installer"
|
33
35
|
require "autoproj/os_package_resolver"
|