Example #1
0
    def __call__(
        self,
        platform: Platform,
        docker_client: DockerClient,
        ros_workspace_dir: Path,
        options: PipelineStageOptions,
        data_collector: DataCollector
    ):
        """
        Run the inspection and output the dependency installation script.

        Also recovers the size of the docker image generated.

        :raises RuntimeError if the step was skipped when no dependency script has been
        previously generated
        """
        gather_rosdeps(
            docker_client=docker_client,
            platform=platform,
            workspace=ros_workspace_dir,
            skip_rosdep_keys=options.skip_rosdep_keys,
            custom_script=options.custom_script,
            custom_data_dir=options.custom_data_dir)
        assert_install_rosdep_script_exists(ros_workspace_dir, platform)

        img_size = docker_client.get_image_size(_IMG_NAME)
        data_collector.add_size(self.name, img_size)
Example #2
0
    def __call__(self, platform: Platform, docker_client: DockerClient,
                 ros_workspace_dir: Path, options: PipelineStageOptions,
                 data_collector: DataCollector):
        create_workspace_sysroot_image(docker_client, platform)

        img_size = docker_client.get_image_size(platform.sysroot_image_tag)
        data_collector.add_size(self.name, img_size)
Example #3
0
def test_timer_can_time():
    test_collector = DataCollector()
    with test_collector.timer('test_time'):
        pass

    assert test_collector._data[0].complete
    assert test_collector._data[0].value > 0
Example #4
0
def test_timer_error_handling():
    test_collector = DataCollector()
    # The timer should not hide the exception, we expect it to add the datum value
    with pytest.raises(Exception):
        with test_collector.timer('test_time_fail'):
            raise Exception

    assert len(test_collector._data) > 0
    assert test_collector._data[0].complete is False
Example #5
0
def main():
    """Start the cross-compilation workflow."""
    args = parse_args(sys.argv[1:])
    ros_workspace_dir = _resolve_ros_workspace(args.ros_workspace)
    data_collector = DataCollector()
    data_writer = DataWriter(ros_workspace_dir)

    try:
        with data_collector.timer('cross_compile_end_to_end'):
            cross_compile_pipeline(args, data_collector)
    finally:
        data_writer.write(data_collector)
def test_data_printing(tmp_path, capfd):
    platform = Platform('aarch64', 'ubuntu', 'foxy')
    test_collector = DataCollector()
    test_datum_a = Datum('test_stat_1', 3, 'tests', 130.243, True)
    test_collector.add_datum(test_datum_a)

    test_writer = DataWriter(tmp_path, 'test.json')
    test_writer.write(test_collector, platform, True)

    out, err = capfd.readouterr()
    test_name = '------------'

    assert test_name in out
def main():
    """Start the cross-compilation workflow."""
    args = parse_args(sys.argv[1:])
    platform = Platform(args.arch, args.os, args.rosdistro,
                        args.sysroot_base_image)
    ros_workspace_dir = _resolve_ros_workspace(args.ros_workspace)
    data_collector = DataCollector()
    data_writer = DataWriter(ros_workspace_dir, args.custom_metric_file)

    try:
        with data_collector.timer('end_to_end'):
            cross_compile_pipeline(args, data_collector, platform)
    finally:
        data_writer.write(data_collector, platform, args.print_metrics)
Example #8
0
def test_bad_workspace(tmpdir):
    args = parse_args(
        [str(tmpdir), '-a', 'aarch64', '-o', 'ubuntu', '-d', 'foxy'])
    test_collector = DataCollector()
    platform = Platform(args.arch, args.os, args.rosdistro)
    with pytest.raises(ValueError):
        cross_compile_pipeline(args, test_collector, platform)
Example #9
0
def cross_compile_pipeline(
    args: argparse.Namespace,
    data_collector: DataCollector,
):
    platform = Platform(args.arch, args.os, args.rosdistro,
                        args.sysroot_base_image)

    ros_workspace_dir = _resolve_ros_workspace(args.ros_workspace)
    skip_rosdep_keys = args.skip_rosdep_keys
    custom_data_dir = _path_if(args.custom_data_dir)
    custom_rosdep_script = _path_if(args.custom_rosdep_script)
    custom_setup_script = _path_if(args.custom_setup_script)

    sysroot_build_context = prepare_docker_build_environment(
        platform=platform,
        ros_workspace=ros_workspace_dir,
        custom_setup_script=custom_setup_script,
        custom_data_dir=custom_data_dir)
    docker_client = DockerClient(args.sysroot_nocache,
                                 default_docker_dir=sysroot_build_context,
                                 colcon_defaults_file=args.colcon_defaults)

    stages = [DependenciesStage(), CreateSysrootStage(), DockerBuildStage()]
    customizations = PipelineStageConfigOptions(args.skip_rosdep_collection,
                                                skip_rosdep_keys,
                                                custom_rosdep_script,
                                                custom_data_dir,
                                                custom_setup_script)

    for stage in stages:
        with data_collector.timer('cross_compile_{}'.format(stage.name)):
            stage(platform, docker_client, ros_workspace_dir, customizations)
def cross_compile_pipeline(
    args: argparse.Namespace,
    data_collector: DataCollector,
    platform: Platform,
):
    ros_workspace_dir = _resolve_ros_workspace(args.ros_workspace)
    skip_rosdep_keys = args.skip_rosdep_keys
    custom_data_dir = _path_if(args.custom_data_dir)
    custom_rosdep_script = _path_if(args.custom_rosdep_script)
    custom_setup_script = _path_if(args.custom_setup_script)

    sysroot_build_context = prepare_docker_build_environment(
        platform=platform,
        ros_workspace=ros_workspace_dir,
        custom_setup_script=custom_setup_script,
        custom_data_dir=custom_data_dir)
    docker_client = DockerClient(args.sysroot_nocache,
                                 default_docker_dir=sysroot_build_context,
                                 colcon_defaults_file=args.colcon_defaults)

    options = PipelineStageOptions(skip_rosdep_keys, custom_rosdep_script,
                                   custom_data_dir, custom_setup_script)

    for stage in _PIPELINE:
        if stage.name not in args.stages_skip:
            with data_collector.timer('{}'.format(stage.name)):
                stage(platform, docker_client, ros_workspace_dir, options,
                      data_collector)
Example #11
0
def test_data_collection():
    test_collector = DataCollector()

    test_datum_a = Datum('test_stat_1', 3, 'tests', 130.452, True)
    test_datum_b = Datum('test_stat_2', 4, 'tests', 130.455, True)

    test_collector.add_datum(test_datum_a)
    test_collector.add_datum(test_datum_b)

    to_test_data = test_collector._data

    assert to_test_data[0].name == 'test_stat_1'
    assert to_test_data[1].name == 'test_stat_2'
    assert to_test_data[0].value == 3
    assert to_test_data[0].unit == 'tests'
    assert abs(to_test_data[0].timestamp - 130.452) < 0.1
    assert to_test_data[0].complete
Example #12
0
def test_data_writing(tmp_path):
    def load_json_validation(filename: Path) -> bool:
        try:
            with filename.open() as f:
                json.load(f)
                return True
        except JSONDecodeError:
            return False

    test_collector = DataCollector()

    test_datum_a = Datum('test_stat_1', 3, 'tests', 130.243, True)
    test_datum_b = Datum('test_stat_2', 4, 'tests', 130.244, True)

    test_collector.add_datum(test_datum_a)
    test_collector.add_datum(test_datum_b)

    test_writer = DataWriter(tmp_path)

    test_writer.write(test_collector)

    assert test_writer.write_file.exists()
    assert load_json_validation(test_writer.write_file)
Example #13
0
def test_mocked_cc_pipeline(tmpdir):
    tmp = Path(str(tmpdir))
    test_collector = DataCollector()
    (tmp / 'src').mkdir()
    args = parse_args([str(tmpdir), '-a', 'aarch64', '-o', 'ubuntu'])
    with patch('ros_cross_compile.ros_cross_compile.DockerClient', Mock(
    )) as docker_mock, patch(
            'ros_cross_compile.dependencies.assert_install_rosdep_script_exists'
    ) as script_mock:
        cross_compile_pipeline(args, test_collector)
        assert script_mock.called
        assert docker_mock.called
        assert docker_mock().build_image.call_count == 2
        assert docker_mock().run_container.call_count == 2
Example #14
0
def buildable_env(request, tmpdir):
    """Set up a temporary directory with everything needed to run the EmulatedDockerBuildStage."""
    platform = Platform('aarch64', 'ubuntu', 'foxy')
    ros_workspace = Path(str(tmpdir)) / 'ros_ws'
    _touch_anywhere(ros_workspace / rosdep_install_script(platform))
    build_context = prepare_docker_build_environment(platform, ros_workspace)
    docker = DockerClient(disable_cache=False,
                          default_docker_dir=build_context)
    options = default_pipeline_options()
    data_collector = DataCollector()

    CreateSysrootStage()(platform, docker, ros_workspace, options,
                         data_collector)

    return BuildableEnv(platform, docker, ros_workspace, options,
                        data_collector)
Example #15
0
def test_relative_workspace(tmpdir):
    # Change directory to the tmp dir and invoke using '.' as the
    # workspace to check if relative paths work
    tmp = Path(str(tmpdir))
    test_collector = DataCollector()
    (tmp / 'src').mkdir()
    relative_dir = '.'
    args = parse_args(
        [relative_dir, '-a', 'aarch64', '-o', 'ubuntu', '-d', 'foxy'])
    with chdir(str(tmp)), patch(
            'ros_cross_compile.ros_cross_compile.DockerClient', Mock()
    ), patch(
            'ros_cross_compile.dependencies.assert_install_rosdep_script_exists'
    ):
        # should not raise an exception
        cross_compile_pipeline(args, test_collector)
Example #16
0
def test_dummy_ros2_pkg(tmpdir):
    ws = Path(str(tmpdir))
    pkg_xml = ws / 'src' / 'dummy' / 'package.xml'
    pkg_xml.parent.mkdir(parents=True)
    pkg_xml.write_text(RCLCPP_PKG_XML)

    client = DockerClient()
    platform = Platform(arch='aarch64', os_name='ubuntu', ros_distro='dashing')
    out_script = ws / rosdep_install_script(platform)
    test_collector = DataCollector()

    stage = CollectDependencyListStage()
    stage(platform, client, ws, default_pipeline_options(), test_collector)

    result = out_script.read_text()
    assert 'ros-dashing-ament-cmake' in result
    assert 'ros-dashing-rclcpp' in result
Example #17
0
def cross_compile_pipeline(
    args: argparse.Namespace,
    data_collector: DataCollector,
    platform: Platform,
):
    ros_workspace_dir = _resolve_ros_workspace(args.ros_workspace)
    skip_rosdep_keys = args.skip_rosdep_keys
    custom_data_dir = _path_if(args.custom_data_dir)
    custom_rosdep_script = _path_if(args.custom_rosdep_script)
    custom_setup_script = _path_if(args.custom_setup_script)
    custom_post_build_script = _path_if(args.custom_post_build_script)
    colcon_defaults_file = _path_if(args.colcon_defaults)

    sysroot_build_context = prepare_docker_build_environment(
        platform=platform,
        ros_workspace=ros_workspace_dir,
        custom_setup_script=custom_setup_script,
        custom_post_build_script=custom_post_build_script,
        colcon_defaults_file=colcon_defaults_file,
        custom_data_dir=custom_data_dir)
    docker_client = DockerClient(args.sysroot_nocache,
                                 default_docker_dir=sysroot_build_context)

    options = PipelineStageOptions(skip_rosdep_keys, custom_rosdep_script,
                                   custom_data_dir, custom_setup_script,
                                   args.runtime_tag)

    skip = set(args.stages_skip)

    # Only package the runtime image if the user has specified a tag for it
    if not args.runtime_tag:
        skip.add(PackageRuntimeImageStage.NAME)

    for stage in _PIPELINE:
        if stage.name not in skip:
            with data_collector.timer('{}'.format(stage.name)):
                stage(platform, docker_client, ros_workspace_dir, options,
                      data_collector)
Example #18
0
def test_custom_post_build_script(tmpdir):
    created_filename = 'file-created-by-post-build'
    platform = Platform('aarch64', 'ubuntu', 'foxy')
    ros_workspace = Path(str(tmpdir)) / 'ros_ws'
    _touch_anywhere(ros_workspace / rosdep_install_script(platform))
    post_build_script = ros_workspace / 'post_build'
    post_build_script.write_text("""
    #!/bin/bash
    echo "success" > {}
    """.format(created_filename))
    build_context = prepare_docker_build_environment(
        platform, ros_workspace, custom_post_build_script=post_build_script)
    docker = DockerClient(disable_cache=False,
                          default_docker_dir=build_context)
    options = default_pipeline_options()
    data_collector = DataCollector()

    CreateSysrootStage()(platform, docker, ros_workspace, options,
                         data_collector)
    EmulatedDockerBuildStage()(platform, docker, ros_workspace, options,
                               data_collector)

    assert (ros_workspace / created_filename).is_file()
Example #19
0
def test_collector_construction():
    test_collector = DataCollector()
    assert test_collector