Skip to content

Commit

Permalink
Add substitution for finding package share directory (#57)
Browse files Browse the repository at this point in the history
* Add substitution for finding package share directory

Expose FindPackageShare as 'find-pkg-share' and FindPackagePrefix as 'find-pkg-prefix'.

This turns

    <include file="$(find-pkg foo)/share/foo/launch/foo.launch.xml">

into

    <include file="$(find-pkg-share foo)/launch/foo.launch.xml">

Signed-off-by: Jacob Perron <jacob@openrobotics.org>

* Refactor to use abstract class

FindPackage is now an abstract class that requires subclasses to implement a 'find' method.
FindPackagePrefix is the subclass that finds the package prefix.

Signed-off-by: Jacob Perron <jacob@openrobotics.org>

* Update error message and describe() method

Signed-off-by: Jacob Perron <jacob@openrobotics.org>
  • Loading branch information
jacobperron authored Sep 11, 2019
1 parent 13e7bf6 commit 897cae8
Show file tree
Hide file tree
Showing 4 changed files with 72 additions and 16 deletions.
4 changes: 4 additions & 0 deletions launch_ros/launch_ros/substitutions/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,13 @@

from .executable_in_package import ExecutableInPackage
from .find_package import FindPackage
from .find_package import FindPackagePrefix
from .find_package import FindPackageShare


__all__ = [
'ExecutableInPackage',
'FindPackage',
'FindPackagePrefix',
'FindPackageShare',
]
4 changes: 2 additions & 2 deletions launch_ros/launch_ros/substitutions/executable_in_package.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,11 +29,11 @@

from osrf_pycommon.process_utils import which

from .find_package import FindPackage
from .find_package import FindPackagePrefix


@expose_substitution('exec-in-pkg')
class ExecutableInPackage(FindPackage):
class ExecutableInPackage(FindPackagePrefix):
"""
Substitution that tries to locate an executable in the libexec directory of a ROS package.
Expand Down
63 changes: 53 additions & 10 deletions launch_ros/launch_ros/substitutions/find_package.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
from typing import Text

from ament_index_python.packages import get_package_prefix
from ament_index_python.packages import get_package_share_directory

from launch.frontend import expose_substitution
from launch.launch_context import LaunchContext
Expand All @@ -28,18 +29,17 @@
from launch.utilities import perform_substitutions


@expose_substitution('find-pkg')
class FindPackage(Substitution):
"""
Substitution that tries to locate the package prefix of a ROS package.
The ROS package is located using ament_index_python.
Abstract base class for substitutions involving finding a package.
:raise: ament_index_python.packages.PackageNotFoundError when package is
not found during substitution.
Subclasses should implement the find() method.
"""

def __init__(self, package: SomeSubstitutionsType) -> None:
def __init__(
self,
package: SomeSubstitutionsType,
) -> None:
"""Constructor."""
super().__init__()
self.__package = normalize_to_list_of_substitutions(package)
Expand All @@ -48,7 +48,7 @@ def __init__(self, package: SomeSubstitutionsType) -> None:
def parse(cls, data: Iterable[SomeSubstitutionsType]):
"""Parse a FindPackage substitution."""
if not data or len(data) != 1:
raise AttributeError('find-package substitution expects 1 argument')
raise AttributeError('find package substitutions expect 1 argument')
kwargs = {'package': data[0]}
return cls, kwargs

Expand All @@ -57,13 +57,56 @@ def package(self) -> List[Substitution]:
"""Getter for package."""
return self.__package

def find(self, package_name: Text) -> Text:
"""
Find a directory for a package.
Called when the substitution is performed.
:param: package_name The name of the package.
:return: A directory related to the package.
"""
raise NotImplementedError()

def describe(self) -> Text:
"""Return a description of this substitution as a string."""
pkg_str = ' + '.join([sub.describe() for sub in self.package])
return 'Pkg(pkg={})'.format(pkg_str)
return '{}(pkg={})'.format(self.__class__.__name__, pkg_str)

def perform(self, context: LaunchContext) -> Text:
"""Perform the substitution by locating the package."""
package = perform_substitutions(context, self.package)
result = get_package_prefix(package)
result = self.find(package)
return result


@expose_substitution('find-pkg-prefix')
class FindPackagePrefix(FindPackage):
"""
Substitution that tries to locate the package prefix of a ROS package.
The ROS package is located using ament_index_python.
:raise: ament_index_python.packages.PackageNotFoundError when package is
not found during substitution.
"""

def find(self, package_name: Text) -> Text:
"""Find the package prefix."""
return get_package_prefix(package_name)


@expose_substitution('find-pkg-share')
class FindPackageShare(FindPackage):
"""
Substitution that tries to locate the share directory of a ROS package.
The directory is located using ament_index_python.
:raise: ament_index_python.packages.PackageNotFoundError when package is
not found during substitution.
"""

def find(self, package_name: Text) -> Text:
"""Find the share directory of a package."""
return get_package_share_directory(package_name)
Original file line number Diff line number Diff line change
Expand Up @@ -12,18 +12,27 @@
# See the License for the specific language governing permissions and
# limitations under the License.

"""Test for the FindPackage substitution."""
"""Test for the FindPackage substitutions."""

from pathlib import Path

from launch import LaunchContext

from launch_ros.substitutions import FindPackage
from launch_ros.substitutions import FindPackagePrefix
from launch_ros.substitutions import FindPackageShare


def test_find_package():
sub = FindPackage('launch_ros')
def test_find_package_prefix():
sub = FindPackagePrefix('launch_ros')
context = LaunchContext()
package_prefix = Path(sub.perform(context))
package_xml_file = package_prefix / Path('share/launch_ros/package.xml')
assert package_xml_file.is_file()


def test_find_package_share():
sub = FindPackageShare('launch_ros')
context = LaunchContext()
package_prefix = Path(sub.perform(context))
package_xml_file = package_prefix / Path('package.xml')
assert package_xml_file.is_file()

0 comments on commit 897cae8

Please sign in to comment.