module Autoproj
# Access to the information contained in a package's manifest.xml file
#
# Use PackageManifest.load to create
class PackageManifest
# Load a manifest.xml file and returns the corresponding
# PackageManifest object
def self.load(package, file)
doc =
begin REXML::Document.new(File.read(file))
rescue REXML::ParseException => e
raise Autobuild::PackageException.new(package.name, 'prepare'), "invalid #{file}: #{e.message}"
end
PackageManifest.new(package, doc)
end
# The Autobuild::Package instance this manifest applies on
attr_reader :package
# The raw XML data as a Nokogiri document
attr_reader :xml
# The list of tags defined for this package
#
# Tags are defined as multiple blocks, each of which can
# contain multiple comma-separated tags
def tags
result = []
xml.elements.each('package/tags') do |node|
result.concat((node.text || "").strip.split(','))
end
result
end
def has_documentation?
xml.elements.each('package/description') do |node|
doc = (node.text || "").strip
if !doc.empty?
return true
end
end
return false
end
def documentation
xml.elements.each('package/description') do |node|
doc = (node.text || "").strip
if !doc.empty?
return doc
end
end
return short_documentation
end
def short_documentation
xml.elements.each('package/description') do |node|
doc = node.attributes['brief']
if doc
doc = doc.to_s.strip
end
if doc && !doc.empty?
return doc.to_s
end
end
"no documentation available for #{package.name} in its manifest.xml file"
end
def initialize(package, doc = REXML::Document.new)
@package = package
@xml = doc
end
def each_dependency(in_modes = Array.new, &block)
return enum_for(__method__) if !block_given?
depend_nodes = xml.elements.to_a('package/depend') +
xml.elements.to_a('package/depend_optional') +
xml.elements.to_a('package/rosdep')
in_modes.each do |m|
depend_nodes += xml.elements.to_a("package/#{m}_depend")
end
depend_nodes.each do |node|
dependency = node.attributes['package'] || node.attributes['name']
optional = (node.attributes['optional'].to_s == '1' || node.name == "depend_optional")
modes = node.attributes['modes'].to_s.split(',')
if node.name =~ /^(\w+)_depend$/
modes << $1
end
if !modes.empty? && modes.none? { |m| in_modes.include?(m) }
next
end
if dependency
yield(dependency, optional)
elsif node.name == 'rosdep'
raise ConfigError.new, "manifest of #{package.name} has a tag without a 'name' attribute"
else
raise ConfigError.new, "manifest of #{package.name} has a <#{node.name}> tag without a 'package' attribute"
end
end
package.os_packages.each do |name|
yield(name, false)
end
end
def each_os_dependency(modes = Array.new, &block)
Autoproj.warn "PackageManifest#each_os_dependency called, fix your code"
return each_dependency(modes, &block)
end
def each_package_dependency(modes = Array.new)
Autoproj.warn "PackageManifest#each_os_dependency called, fix your code"
return each_dependency(modes, &block)
end
def each_maintainer
if !block_given?
return enum_for(:each_maintainer)
end
xml.elements.each('package/maintainer') do |maintainer|
(maintainer.text || "").strip.split(',').each do |str|
name, email = str.split('/').map(&:strip)
email = nil if email && email.empty?
yield(name, email)
end
end
end
# Enumerates the name and email of each author. If no email is present,
# yields (name, nil)
def each_author
if !block_given?
return enum_for(:each_author)
end
xml.elements.each('package/author') do |author|
(author.text || "").strip.split(',').each do |str|
name, email = str.split('/').map(&:strip)
email = nil if email && email.empty?
yield(name, email)
end
end
end
# If +name+ points to a text element in the XML document, returns the
# content of that element. If no element matches +name+, or if the
# content is empty, returns nil
def text_node(name)
xml.elements.each(name) do |str|
str = (str.text || "").strip
if !str.empty?
return str
end
end
nil
end
# The package associated URL, usually meant to direct to a website
#
# Returns nil if there is none
def url
return text_node('package/url')
end
# The package license name
#
# Returns nil if there is none
def license
return text_node('package/license')
end
# The package version number
#
# Returns 0 if none is declared
def version
return text_node("version")
end
end
end