Example #1
0
 def expand_dict(input_dict):
     expanded_dict = {}
     for k, v in input_dict.items():
         # Key (parameter/group name) can only be a string/Substitutions that evaluates
         # to a string.
         expanded_key = perform_substitutions(
             context, normalize_to_list_of_substitutions(k))
         if isinstance(v, dict):
             # Expand the nested dict.
             expanded_value = expand_dict(v)
         elif isinstance(v, list):
             # Expand each element.
             expanded_value = []
             for e in v:
                 if isinstance(e, list):
                     raise TypeError(
                         'Nested lists are not supported for parameters: {} found in {}'
                         .format(e, v))
                 expanded_value.append(
                     perform_substitution_if_applicable(context, e))
         # Tuples are treated as Substitution(s) to be concatenated.
         elif isinstance(v, tuple):
             for e in v:
                 ensure_argument_type(
                     e, SomeSubstitutionsType_types_tuple,
                     'parameter dictionary tuple entry', 'Node')
             expanded_value = perform_substitutions(
                 context, normalize_to_list_of_substitutions(v))
         else:
             expanded_value = perform_substitution_if_applicable(
                 context, v)
         expanded_dict[expanded_key] = expanded_value
     return expanded_dict
Example #2
0
    def evaluate(self, context: LaunchContext) -> Path:
        """Evaluate and return a parameter file path."""
        if self.__evaluated_param_file is not None:
            return self.__evaluated_param_file

        param_file = self.__param_file
        if isinstance(param_file, list):
            # list of substitutions
            param_file = perform_substitutions(context, self.__param_file)

        allow_substs = perform_typed_substitution(context,
                                                  self.__allow_substs,
                                                  data_type=bool)
        param_file_path: Path = Path(param_file)
        if allow_substs:
            with open(param_file_path,
                      'r') as f, NamedTemporaryFile(mode='w',
                                                    prefix='launch_params_',
                                                    delete=False) as h:
                parsed = perform_substitutions(context,
                                               parse_substitution(f.read()))
                try:
                    yaml.safe_load(parsed)
                except Exception:
                    raise SubstitutionFailure(
                        'The substituted parameter file is not a valid yaml file'
                    )
                h.write(parsed)
                param_file_path = Path(h.name)
                self.__created_tmp_file = True
        self.__evaluated_param_file = param_file_path
        return param_file_path
Example #3
0
 def execute(self, context: LaunchContext):
     """Execute the action."""
     src = perform_substitutions(context, self.__src)
     dst = perform_substitutions(context, self.__dst)
     global_remaps = context.launch_configurations.get('ros_remaps', [])
     global_remaps.append((src, dst))
     context.launch_configurations['ros_remaps'] = global_remaps
    def _load_nodes_in_docker(self, context: LaunchContext) -> None:
        """Load all nodes into Docker container."""
        if self._container is None:
            self.__logger.error('Unable to load nodes into Docker container: '
                                'no active Docker container!')
            return

        for description in self._node_descriptions:
            package_name = perform_substitutions(context=context,
                                                 subs=description.package)

            executable_name = perform_substitutions(
                context=context, subs=description.node_executable)

            cmd = _containerized_cmd(entrypoint=self._policy.entrypoint,
                                     package=package_name,
                                     executable=executable_name)

            self._container.exec_run(
                cmd=cmd,
                detach=True,
                tty=True,
            )

            self.__logger.debug('Running \"{}\" in container: \"{}\"'.format(
                cmd, self._policy.container_name))
Example #5
0
def test_mixed_substitutions():
    lc = LaunchContext()
    rule = (('foo', 'bar'), ['bar', TextSubstitution(text='baz')])
    output_rule = normalize_remap_rule(rule)
    assert isinstance(output_rule, tuple)
    assert len(output_rule) == 2
    assert 'foobar' == perform_substitutions(lc, output_rule[0])
    assert 'barbaz' == perform_substitutions(lc, output_rule[1])
Example #6
0
def test_plain_text():
    lc = LaunchContext()
    rule = ('foo', 'bar')
    output_rule = normalize_remap_rule(rule)
    assert isinstance(output_rule, tuple)
    assert len(output_rule) == 2
    assert rule[0] == perform_substitutions(lc, output_rule[0])
    assert rule[1] == perform_substitutions(lc, output_rule[1])
Example #7
0
def test_multiple_rules():
    lc = LaunchContext()
    rules = [('ping', 'pong'),
             (('baz', 'foo'), ['bar', TextSubstitution(text='baz')])]
    output_rules = list(normalize_remap_rules(rules))
    assert len(rules) == len(output_rules)
    assert 'ping' == perform_substitutions(lc, output_rules[0][0])
    assert 'pong' == perform_substitutions(lc, output_rules[0][1])
    assert 'bazfoo' == perform_substitutions(lc, output_rules[1][0])
    assert 'barbaz' == perform_substitutions(lc, output_rules[1][1])
Example #8
0
    def apply(
        self,
        context: LaunchContext,
        node_descriptions: List[SandboxedNode]
    ) -> Action:
        """Apply the policy any launches the ROS2 nodes in the sandbox."""
        user = self.run_as
        pw_record = pwd.getpwuid(user.uid)

        env = os.environ.copy()
        env['HOME'] = pw_record.pw_dir
        env['LOGNAME'] = pw_record.pw_name
        env['USER'] = pw_record.pw_name
        self.__logger.debug('Running as: {}'.format(pw_record.pw_name))
        self.__logger.debug('\tuid: {}'.format(user.uid))
        self.__logger.debug('\tgid: {}'.format(user.gid))
        self.__logger.debug('\thome: {}'.format(pw_record.pw_dir))

        def set_user() -> None:
            """Set the current user."""
            os.setgid(user.gid)
            os.setuid(user.uid)

        for description in node_descriptions:
            package_name = perform_substitutions(
                context,
                description.package
            )
            executable_name = perform_substitutions(
                context,
                description.node_executable
            )

            # TODO: support node namespace and node name
            # TODO: support parameters
            # TODO: support remappings

            cmd = [ExecutableInPackage(
                package=package_name,
                executable=executable_name
            ).perform(context)]

            self.__logger.info('Running: {}'.format(cmd))

            subprocess.Popen(
                cmd,
                preexec_fn=set_user,
                env=env
            )

            # TODO: handle events for process

        # TODO: LaunchAsUser is currently NO-OP due to all sandboxing logic being handled here.
        return LoadRunAsNodes()
Example #9
0
def test_log_info_methods():
    """Test the methods of the LogInfo class."""
    launch_context = LaunchContext()

    log_info = LogInfo(msg='')
    assert perform_substitutions(launch_context, log_info.msg) == ''

    log_info = LogInfo(msg='foo')
    assert perform_substitutions(launch_context, log_info.msg) == 'foo'

    log_info = LogInfo(msg=['foo', 'bar', 'baz'])
    assert perform_substitutions(launch_context, log_info.msg) == 'foobarbaz'
Example #10
0
def test_valid_substitutions():
    """Test the perform_substitutions() function with valid input."""
    context = LaunchContext()

    class MockSubstitution(Substitution):
        def perform(self, context):
            return 'Mock substitution'

    mock_sub = MockSubstitution()
    sub_mock_sub = perform_substitutions(context, [mock_sub])
    assert 'Mock substitution' == sub_mock_sub
    sub_mock_sub_multi = perform_substitutions(context,
                                               [mock_sub, mock_sub, mock_sub])
    assert 'Mock substitutionMock substitutionMock substitution' == sub_mock_sub_multi
def get_composable_node_load_request(
        composable_node_description: ComposableNode, context: LaunchContext):
    """Get the request that will be send to the composable node container."""
    request = composition_interfaces.srv.LoadNode.Request()
    request.package_name = perform_substitutions(
        context, composable_node_description.package)
    request.plugin_name = perform_substitutions(
        context, composable_node_description.node_plugin)
    if composable_node_description.node_name is not None:
        request.node_name = perform_substitutions(
            context, composable_node_description.node_name)
    expanded_ns = composable_node_description.node_namespace
    if expanded_ns is not None:
        expanded_ns = perform_substitutions(context, expanded_ns)
    base_ns = context.launch_configurations.get('ros_namespace', None)
    combined_ns = make_namespace_absolute(
        prefix_namespace(base_ns, expanded_ns))
    if combined_ns is not None:
        request.node_namespace = combined_ns
    # request.log_level = perform_substitutions(context, node_description.log_level)
    remappings = []
    global_remaps = context.launch_configurations.get('ros_remaps', None)
    if global_remaps:
        remappings.extend([f'{src}:={dst}' for src, dst in global_remaps])
    if composable_node_description.remappings:
        remappings.extend([
            f'{perform_substitutions(context, src)}:={perform_substitutions(context, dst)}'
            for src, dst in composable_node_description.remappings
        ])
    if remappings:
        request.remap_rules = remappings
    global_params = context.launch_configurations.get('ros_params', None)
    parameters = []
    if global_params is not None:
        parameters.append(normalize_parameter_dict(global_params))
    if composable_node_description.parameters is not None:
        parameters.extend(list(composable_node_description.parameters))
    if parameters:
        request.parameters = [
            param.to_parameter_msg() for param in to_parameters_list(
                context, evaluate_parameters(context, parameters))
        ]
    if composable_node_description.extra_arguments is not None:
        request.extra_arguments = [
            param.to_parameter_msg() for param in to_parameters_list(
                context,
                evaluate_parameters(
                    context, composable_node_description.extra_arguments))
        ]
    return request
Example #12
0
def evaluate_parameters(context: LaunchContext,
                        parameters: Parameters) -> EvaluatedParameters:
    """
    Evaluate substitutions to produce paths and name/value pairs.

    The parameters must have been normalized with normalize_parameters() prior to calling this.
    Substitutions for parameter values in dictionaries will be evaluated according to yaml rules.
    If you want the substitution to stay a string, the output of the substition must have quotes.

    :param parameters: normalized parameters
    :returns: values after evaluating lists of substitutions
    """
    output_params = [
    ]  # type: List[Union[pathlib.Path, Dict[str, EvaluatedParameterValue]]]
    for param in parameters:
        # If it's a list of substitutions then evaluate them to a string and return a pathlib.Path
        if isinstance(param, tuple) and len(param) and isinstance(
                param[0], Substitution):
            # Evaluate a list of Substitution to a file path
            output_params.append(
                pathlib.Path(perform_substitutions(context, list(param))))
        elif isinstance(param, Mapping):
            # It's a list of name/value pairs
            output_params.append(evaluate_parameter_dict(context, param))
    return tuple(output_params)
 def execute(self, context: LaunchContext):
     """Execute the action."""
     filename = perform_substitutions(context, self._input_file)
     global_param_list = context.launch_configurations.get(
         'global_params', [])
     global_param_list.append(filename)
     context.launch_configurations['global_params'] = global_param_list
Example #14
0
def test_set_param_with_node():
    lc = MockContext()
    node = Node(package='asd',
                executable='bsd',
                name='my_node',
                namespace='my_ns',
                parameters=[{
                    'asd': 'bsd'
                }])
    set_param = SetParameter(name='my_param', value='my_value')
    set_param.execute(lc)
    node._perform_substitutions(lc)
    actual_command = [
        perform_substitutions(lc, item) for item in node.cmd
        if type(item[0]) == TextSubstitution
    ]
    assert actual_command.count('--params-file') == 1
    assert actual_command.count('-p') == 1

    param_cmdline_index = actual_command.index('-p') + 1
    param_cmdline = actual_command[param_cmdline_index]
    assert param_cmdline == 'my_param:=my_value'

    param_file_index = actual_command.index('--params-file') + 1
    param_file_path = actual_command[param_file_index]
    assert os.path.isfile(param_file_path)
    with open(param_file_path, 'r') as h:
        expanded_parameters_dict = yaml.load(h, Loader=yaml.FullLoader)
        assert expanded_parameters_dict == {
            '/my_ns/my_node': {
                'ros__parameters': {
                    'asd': 'bsd'
                }
            }
        }
    def execute(self, context: LaunchContext) -> Optional[List[Action]]:
        """Execute the action."""
        # resolve target container node name

        if is_a_subclass(self.__target_container, ComposableNodeContainer):
            self.__final_target_container_name = self.__target_container.node_name
        elif isinstance(self.__target_container,
                        SomeSubstitutionsType_types_tuple):
            subs = normalize_to_list_of_substitutions(self.__target_container)
            self.__final_target_container_name = perform_substitutions(
                context, subs)
        else:
            self.__logger.error(
                'target container is neither a ComposableNodeContainer nor a SubstitutionType'
            )
            return

        # Create a client to load nodes in the target container.
        self.__rclpy_load_node_client = get_ros_node(context).create_client(
            composition_interfaces.srv.LoadNode,
            '{}/_container/load_node'.format(
                self.__final_target_container_name))

        # Generate load requests before execute() exits to avoid race with context changing
        # due to scope change (e.g. if loading nodes from within a GroupAction).
        load_node_requests = [
            get_composable_node_load_request(node_description, context)
            for node_description in self.__composable_node_descriptions
        ]

        context.add_completion_future(
            context.asyncio_loop.run_in_executor(None, self._load_in_sequence,
                                                 load_node_requests, context))
Example #16
0
    def execute(
        self,
        context: LaunchContext
    ) -> Optional[List[Action]]:
        """Execute the action."""
        # resolve target container node name

        if is_a_subclass(self.__target_container, ComposableNodeContainer):
            self.__final_target_container_name = self.__target_container.node_name
        elif isinstance(self.__target_container, SomeSubstitutionsType_types_tuple):
            subs = normalize_to_list_of_substitutions(self.__target_container)
            self.__final_target_container_name = perform_substitutions(
                context, subs)
        else:
            self.__logger.error(
                'target container is neither a ComposableNodeContainer nor a SubstitutionType')
            return

        # Create a client to load nodes in the target container.
        self.__rclpy_load_node_client = get_ros_node(context).create_client(
            composition_interfaces.srv.LoadNode, '{}/_container/load_node'.format(
                self.__final_target_container_name
            )
        )

        context.add_completion_future(
            context.asyncio_loop.run_in_executor(
                None, self._load_in_sequence, self.__composable_node_descriptions, context
            )
        )
 def perform(self, context: LaunchContext) -> Text:
     """Perform the substitution by locating the executable."""
     executable = perform_substitutions(context, self.executable)
     package = perform_substitutions(context, self.package)
     package_prefix = super().perform(context)
     package_libexec = os.path.join(package_prefix, 'lib', package)
     if not os.path.exists(package_libexec):
         raise SubstitutionFailure(
             "package '{}' found at '{}', but libexec directory '{}' does not exist"
             .format(package, package_prefix, package_libexec))
     result = which(executable, path=package_libexec)
     if result is None:
         raise SubstitutionFailure(
             "executable '{}' not found on the libexec directory '{}' ".
             format(executable, package_libexec))
     return result
Example #18
0
def test_include_launch_description_launch_arguments():
    """Test the interactions between declared launch arguments and IncludeLaunchDescription."""
    # test that arguments are set when given, even if they are not declared
    ld1 = LaunchDescription([])
    action1 = IncludeLaunchDescription(
        LaunchDescriptionSource(ld1),
        launch_arguments={'foo': 'FOO'}.items(),
    )
    assert len(action1.launch_arguments) == 1
    lc1 = LaunchContext()
    result1 = action1.visit(lc1)
    assert len(result1) == 2
    assert isinstance(result1[0], SetLaunchConfiguration)
    assert perform_substitutions(lc1, result1[0].name) == 'foo'
    assert perform_substitutions(lc1, result1[0].value) == 'FOO'
    assert result1[1] == ld1

    # test that a declared argument that is not provided raises an error
    ld2 = LaunchDescription([DeclareLaunchArgument('foo')])
    action2 = IncludeLaunchDescription(LaunchDescriptionSource(ld2))
    lc2 = LaunchContext()
    with pytest.raises(RuntimeError) as excinfo2:
        action2.visit(lc2)
    assert 'Included launch description missing required argument' in str(
        excinfo2)

    # test that a declared argument that is not provided raises an error, but with other args set
    ld2 = LaunchDescription([DeclareLaunchArgument('foo')])
    action2 = IncludeLaunchDescription(
        LaunchDescriptionSource(ld2),
        launch_arguments={'not_foo': 'NOT_FOO'}.items(),
    )
    lc2 = LaunchContext()
    with pytest.raises(RuntimeError) as excinfo2:
        action2.visit(lc2)
    assert 'Included launch description missing required argument' in str(
        excinfo2)
    assert 'not_foo' in str(excinfo2)

    # test that a declared argument with a default value that is not provided does not raise
    ld2 = LaunchDescription(
        [DeclareLaunchArgument('foo', default_value='FOO')])
    action2 = IncludeLaunchDescription(LaunchDescriptionSource(ld2))
    lc2 = LaunchContext()
    action2.visit(lc2)
Example #19
0
File: node.py Project: hfz-Nick/ROS
 def _perform_substitutions(self, context: LaunchContext) -> None:
     try:
         if self.__substitutions_performed:
             # This function may have already been called by a subclass' `execute`, for example.
             return
         self.__substitutions_performed = True
         if self.__node_name is not None:
             self.__expanded_node_name = perform_substitutions(
                 context,
                 normalize_to_list_of_substitutions(self.__node_name))
             validate_node_name(self.__node_name)
         self.__expanded_node_name.lstrip('/')
         if self.__node_namespace is not None:
             self.__expanded_node_namespace = perform_substitutions(
                 context,
                 normalize_to_list_of_substitutions(self.__node_namespace))
         if not self.__expanded_node_namespace.startswith('/'):
             self.__expanded_node_namespace = '/' + self.__expanded_node_namespace
         validate_namespace(self.__expanded_node_namespace)
     except Exception:
         print(
             "Error while expanding or validating node name or namespace for '{}':"
             .format(
                 'package={}, node_executable={}, name={}, namespace={}'.
                 format(
                     self.__package,
                     self.__node_executable,
                     self.__node_name,
                     self.__node_namespace,
                 )))
         raise
     self.__final_node_name = ''
     if self.__expanded_node_namespace not in ['', '/']:
         self.__final_node_name += self.__expanded_node_namespace
     self.__final_node_name += '/' + self.__expanded_node_name
     # expand remappings too
     if self.__remappings is not None:
         self.__expanded_remappings = {}
         for k, v in self.__remappings:
             key = perform_substitutions(
                 context, normalize_to_list_of_substitutions(k))
             value = perform_substitutions(
                 context, normalize_to_list_of_substitutions(v))
             self.__expanded_remappings[key] = value
Example #20
0
 def perform_substitution_if_applicable(context, var):
     if isinstance(var, (int, float, str)):
         # No substitution necessary.
         return var
     if isinstance(var, Substitution):
         return perform_substitutions(
             context, normalize_to_list_of_substitutions(var))
     if isinstance(var, tuple):
         try:
             return perform_substitutions(
                 context, normalize_to_list_of_substitutions(var))
         except TypeError:
             raise TypeError(
                 'Invalid element received in parameters dictionary '
                 '(not all tuple elements are Substitutions): {}'.
                 format(var))
     else:
         raise TypeError(
             'Unsupported type received in parameters dictionary: {}'
             .format(type(var)))
Example #21
0
    def evaluate(
            self,
            context: LaunchContext) -> Tuple[Text, 'EvaluatedParameterValue']:
        """Evaluate and return parameter rule."""
        if self.__evaluated_parameter_rule is not None:
            return self.__evaluated_parameter_rule

        name = perform_substitutions(context, self.name)
        value = self.__parameter_value.evaluate(context)

        self.__evaluated_parameter_name = name
        self.__evaluated_parameter_rule = (name, value)
        return (name, value)
Example #22
0
    def _load_node(self, composable_node_description: ComposableNode,
                   context: LaunchContext) -> None:
        """
        Load node synchronously.

        :param composable_node_description: description of composable node to be loaded
        :param context: current launch context
        """
        while not self.__rclpy_load_node_client.wait_for_service(
                timeout_sec=1.0):
            if context.is_shutdown:
                self.__logger.warning(
                    "Abandoning wait for the '{}' service, due to shutdown.".
                    format(self.__rclpy_load_node_client.srv_name))
                return
        request = composition_interfaces.srv.LoadNode.Request()
        request.package_name = perform_substitutions(
            context, composable_node_description.package)
        request.plugin_name = perform_substitutions(
            context, composable_node_description.node_plugin)
        if composable_node_description.node_name is not None:
            request.node_name = perform_substitutions(
                context, composable_node_description.node_name)
        if composable_node_description.node_namespace is not None:
            request.node_namespace = perform_substitutions(
                context, composable_node_description.node_namespace)
        # request.log_level = perform_substitutions(context, node_description.log_level)
        if composable_node_description.remappings is not None:
            for from_, to in composable_node_description.remappings:
                request.remap_rules.append('{}:={}'.format(
                    perform_substitutions(context, list(from_)),
                    perform_substitutions(context, list(to)),
                ))
        if composable_node_description.parameters is not None:
            request.parameters = [
                param.to_parameter_msg() for param in to_parameters_list(
                    context,
                    evaluate_parameters(
                        context, composable_node_description.parameters))
            ]
        if composable_node_description.extra_arguments is not None:
            request.extra_arguments = [
                param.to_parameter_msg() for param in to_parameters_list(
                    context,
                    evaluate_parameters(
                        context, composable_node_description.extra_arguments))
            ]
        response = self.__rclpy_load_node_client.call(request)
        if not response.success:
            self.__logger.error(
                "Failed to load node '{}' of type '{}' in container '{}': {}".
                format(
                    response.full_node_name
                    if response.full_node_name else request.node_name,
                    request.plugin_name, self.__final_target_container_name,
                    response.error_message))
        self.__logger.info("Loaded node '{}' in container '{}'".format(
            response.full_node_name, self.__final_target_container_name))
Example #23
0
def evaluate_parameter_dict(
    context: LaunchContext,
    parameters: ParametersDict
) -> Dict[str, EvaluatedParameterValue]:
    if not isinstance(parameters, Mapping):
        raise TypeError('expected dict')
    output_dict = {}  # type: Dict[str, EvaluatedParameterValue]
    for name, value in parameters.items():
        if not isinstance(name, tuple):
            raise TypeError('Expecting tuple of substitutions got {}'.format(repr(name)))
        evaluated_name = perform_substitutions(context, list(name))  # type: str
        evaluated_value = None  # type: Optional[EvaluatedParameterValue]

        if isinstance(value, tuple) and len(value):
            if isinstance(value[0], Substitution):
                # Value is a list of substitutions, so perform them to make a string
                evaluated_value = perform_substitutions(context, list(value))
            elif isinstance(value[0], Sequence):
                # Value is an array of a list of substitutions
                output_subvalue = []  # List[str]
                for subvalue in value:
                    output_subvalue.append(perform_substitutions(context, list(subvalue)))
                    evaluated_value = tuple(output_subvalue)
            else:
                # Value is an array of the same type, so nothing to evaluate.
                output_value = []
                target_type = type(value[0])
                for i, subvalue in enumerate(value):
                    output_value.append(target_type(subvalue))
                    evaluated_value = tuple(output_value)
        else:
            # Value is a singular type, so nothing to evaluate
            ensure_argument_type(value, (float, int, str, bool, bytes), 'value')
            evaluated_value = cast(Union[float, int, str, bool, bytes], value)
        if evaluated_value is None:
            raise TypeError('given unnormalized parameters %r, %r' % (name, value))
        output_dict[evaluated_name] = evaluated_value
    return output_dict
Example #24
0
def test_log():
    launch_context = LaunchContext()
    xml_file = \
        """\
        <launch>
            <log message="Hello world!" />
        </launch>
        """
    xml_file = textwrap.dedent(xml_file)
    root_entity, parser = Parser.load(io.StringIO(xml_file))
    launch_description = parser.parse_description(root_entity)
    log_info = launch_description.entities[0]
    assert isinstance(log_info, LogInfo)
    assert perform_substitutions(launch_context,
                                 log_info.msg) == 'Hello world!'
Example #25
0
 def execute(self, context: LaunchContext):
     """Execute the action."""
     pushed_namespace = perform_substitutions(context, self.namespace)
     previous_namespace = context.launch_configurations.get(
         'ros_namespace', None)
     namespace = make_namespace_absolute(
         prefix_namespace(previous_namespace, pushed_namespace))
     try:
         validate_namespace(namespace)
     except Exception:
         raise SubstitutionFailure(
             'The resulting namespace is invalid:'
             " [previous_namespace='{}', pushed_namespace='{}']".format(
                 previous_namespace, pushed_namespace))
     context.launch_configurations['ros_namespace'] = namespace
Example #26
0
def robot_state_publisher(
        context: LaunchContext,
        **substitutions: launch.substitutions.LaunchConfiguration
) -> List[Node]:
    kwargs = {
        k: perform_substitutions(context, [v])
        for k, v in substitutions.items()
    }
    params = {'robot_description': urdf(**kwargs)}
    with open('test.urdf', 'w+') as f:
        f.write(params['robot_description'])
    node = Node(package='robot_state_publisher',
                node_executable='robot_state_publisher',
                node_name='robot_state_publisher',
                parameters=[params],
                output='screen')
    return [node]
 def execute(self, context: LaunchContext):
     """Execute the action."""
     pushed_namespace = perform_substitutions(context, self.namespace)
     previous_namespace = context.launch_configurations.get(
         'ros_namespace', '')
     namespace = pushed_namespace
     if not pushed_namespace.startswith('/'):
         namespace = previous_namespace + '/' + pushed_namespace
     namespace = namespace.rstrip('/')
     if namespace != '':
         try:
             validate_namespace(namespace)
         except Exception:
             raise SubstitutionFailure(
                 'The resulting namespace is invalid:'
                 " [previous_namespace='{}', pushed_namespace='{}']".format(
                     previous_namespace, pushed_namespace))
     context.launch_configurations['ros_namespace'] = namespace
Example #28
0
def get_composable_node_load_request(
    composable_node_description: ComposableNode,
    context: LaunchContext
):
    """Get the request that will be send to the composable node container."""
    request = composition_interfaces.srv.LoadNode.Request()
    request.package_name = perform_substitutions(
        context, composable_node_description.package
    )
    request.plugin_name = perform_substitutions(
        context, composable_node_description.node_plugin
    )
    if composable_node_description.node_name is not None:
        request.node_name = perform_substitutions(
            context, composable_node_description.node_name
        )
    if composable_node_description.node_namespace is not None:
        request.node_namespace = perform_substitutions(
            context, composable_node_description.node_namespace
        )
    # request.log_level = perform_substitutions(context, node_description.log_level)
    if composable_node_description.remappings is not None:
        for from_, to in composable_node_description.remappings:
            request.remap_rules.append('{}:={}'.format(
                perform_substitutions(context, list(from_)),
                perform_substitutions(context, list(to)),
            ))
    global_params = context.launch_configurations.get('ros_params', None)
    parameters = []
    if global_params is not None:
        parameters.append(normalize_parameter_dict(global_params))
    if composable_node_description.parameters is not None:
        parameters.extend(list(composable_node_description.parameters))
    if parameters:
        request.parameters = [
            param.to_parameter_msg() for param in to_parameters_list(
                context, evaluate_parameters(
                    context, parameters
                )
            )
        ]
    if composable_node_description.extra_arguments is not None:
        request.extra_arguments = [
            param.to_parameter_msg() for param in to_parameters_list(
                context, evaluate_parameters(
                    context, composable_node_description.extra_arguments
                )
            )
        ]
    return request
def test_parameter_file_description(original_contents, expected_contents, allow_substs):
    lc = MockContext()
    with get_parameter_file(original_contents) as file_name:
        desc = ParameterFile(file_name, allow_substs=allow_substs)
        if isinstance(desc.param_file, list):
            assert perform_substitutions(lc, desc.param_file) == file_name
        else:
            assert desc.param_file == file_name
        assert desc.allow_substs == allow_substs
        evaluated_param_file = desc.evaluate(lc)
        with open(evaluated_param_file, 'r') as new_f:
            new_f.read() == expected_contents
        assert desc.param_file == evaluated_param_file
        if not allow_substs:
            assert os.fspath(desc.param_file) == os.fspath(file_name)
        param_file = desc.param_file
        desc.cleanup()
        if allow_substs:
            assert not param_file.exists()
            assert isinstance(desc.param_file, list)
        else:
            assert param_file.exists()
            assert os.fspath(desc.param_file) == os.fspath(file_name)
Example #30
0
 def execute(self, context: LaunchContext):
     continue_after_fail = self.__continue_after_fail
     if not isinstance(continue_after_fail, bool):
         continue_after_fail = perform_substitutions(
             context, normalize_to_list_of_substitutions(
                 continue_after_fail)).lower()
         if continue_after_fail in ['true', 'on', '1']:
             continue_after_fail = True
         elif continue_after_fail in ['false', 'off', '1']:
             continue_after_fail = False
         else:
             raise ValueError(
                 'continue_after_fail should be a boolean, got {}'.format(
                     continue_after_fail))
     on_first_action_exited = OnProcessExit(
         target_action=self.__actions[0],
         on_exit=lambda event, context:
         ([InOrderGroup(self.__actions[1:])]
          if event.exitcode == 0 or continue_after_fail else []))
     return [
         self.__actions[0],
         RegisterEventHandler(on_first_action_exited)
     ]