Source code for statick_tool.plugins.discovery.ros_discovery_plugin

"""Discovery plugin to find ROS packages."""
import logging
import os
from functools import reduce
from typing import Any, Dict, Optional, Union

import xmltodict

from statick_tool.discovery_plugin import DiscoveryPlugin
from statick_tool.exceptions import Exceptions
from statick_tool.package import Package


[docs]class RosDiscoveryPlugin(DiscoveryPlugin): """Discovery plugin to find ROS packages."""
[docs] def get_name(self) -> str: """Get name of discovery type.""" return "ros"
[docs] @classmethod def deep_get( cls, dictionary: Union[str, Dict[Any, str]], keys: str, default: Optional[str] = None, ) -> Any: """Safe way to check for a value in a nested dict. Copied from: https://stackoverflow.com/questions/25833613/python-safe-method-to-get-value-of-nested-dictionary """ return reduce( lambda d, key: d.get(key, default) if isinstance(d, dict) else default, keys.split("."), dictionary, )
[docs] def scan( self, package: Package, level: str, exceptions: Optional[Exceptions] = None ) -> None: """Scan package looking for ROS package files.""" cmake_file = os.path.join(package.path, "CMakeLists.txt") package_file = os.path.join(package.path, "package.xml") ros_version = os.getenv("ROS_VERSION") if ( os.path.isfile(cmake_file) and os.path.isfile(package_file) and ros_version is not None ): logging.info(" Package is ROS%s.", ros_version) if ros_version == "1": package["is_ros1"] = True elif ros_version == "2": distro = os.getenv("ROS_DISTRO") path = os.getenv("PATH") if path is not None: for item in path.split(":"): if distro is not None and distro in item: package[ "cmake_flags" ] = "-DCMAKE_PREFIX_PATH=" + item.rstrip("/bin") package["is_ros2"] = True elif os.path.isfile(package_file) and ros_version is not None: with open(package_file, encoding="utf8") as fconfig: try: output = xmltodict.parse(fconfig.read()) except ( xmltodict.expat.ExpatError, xmltodict.ParsingInterrupted, ) as exc: # No valid XML found, so we are not going to find the build type. logging.warning(" Invalid XML in %s: %s", package_file, exc) return if self.deep_get(output, "package.export.build_type") == "ament_python": logging.info(" Package is ROS%s.", ros_version) package["is_ros2"] = True