def main(argv=sys.argv[1:]):
    parser = argparse.ArgumentParser(
        description='Invoke the build tool on a workspace while enabling and '
                    'running the tests')
    parser.add_argument(
        '--rosdistro-name',
        required=True,
        help='The name of the ROS distro to identify the setup file to be '
             'sourced (if available)')
    add_argument_ros_version(parser)
    add_argument_build_tool(parser, required=True)
    a1 = add_argument_build_tool_args(parser)
    a2 = add_argument_build_tool_test_args(parser)
    parser.add_argument(
        '--workspace-root',
        required=True,
        help='The root path of the workspace to compile')
    parser.add_argument(
        '--parent-result-space', nargs='*',
        help='The paths of the parent result spaces')
    parser.add_argument(
        '--clean-before',
        action='store_true',
        help='The flag if the workspace should be cleaned before the '
             'invocation')
    parser.add_argument(
        '--clean-after',
        action='store_true',
        help='The flag if the workspace should be cleaned after the '
             'invocation')
    add_argument_require_gpu_support(parser)

    remainder_args = extract_multiple_remainders(argv, (a1, a2))
    args = parser.parse_args(argv)
    for k, v in remainder_args.items():
        setattr(args, k, v)

    ensure_workspace_exists(args.workspace_root)

    if args.clean_before:
        clean_workspace(args.workspace_root)

    parent_result_spaces = None
    if args.parent_result_space:
        parent_result_spaces = args.parent_result_space

    try:
        with Scope('SUBSECTION', 'build workspace in isolation'):
            test_results_dir = os.path.join(
                args.workspace_root, 'test_results')
            cmake_args = ['-DBUILD_TESTING=1']
            if args.ros_version == 1:
                cmake_args += [
                    '-DCATKIN_ENABLE_TESTING=1', '-DCATKIN_SKIP_TESTING=0',
                    '-DCATKIN_TEST_RESULTS_DIR=%s' % test_results_dir]
            additional_args = args.build_tool_args or []
            if args.build_tool == 'colcon':
                additional_args += ['--test-result-base', test_results_dir]
            env = dict(os.environ)
            env.setdefault('MAKEFLAGS', '-j1')
            rc = call_build_tool(
                args.build_tool, args.rosdistro_name, args.workspace_root,
                cmake_clean_cache=True,
                cmake_args=cmake_args, args=additional_args,
                parent_result_spaces=parent_result_spaces, env=env)
        if not rc:
            with Scope('SUBSECTION', 'build tests'):
                additional_args = args.build_tool_args or []
                if args.build_tool == 'colcon':
                    additional_args += ['--cmake-target-skip-unavailable']
                rc = call_build_tool(
                    args.build_tool, args.rosdistro_name, args.workspace_root,
                    cmake_args=cmake_args,
                    make_args=['tests'], args=additional_args,
                    parent_result_spaces=parent_result_spaces, env=env)
            if not rc:
                make_args = ['run_tests']
                additional_args = args.build_tool_args or []
                if args.build_tool == 'colcon':
                    cmake_args = None
                    make_args = None
                    additional_args = ['--test-result-base', test_results_dir]
                additional_args += args.build_tool_test_args or []
                # for workspaces with only plain cmake packages the setup files
                # generated by cmi won't implicitly source the underlays
                if parent_result_spaces is None:
                    parent_result_spaces = ['/opt/ros/%s' % args.rosdistro_name]
                if args.build_tool == 'catkin_make_isolated':
                    devel_space = os.path.join(
                        args.workspace_root, 'devel_isolated')
                    parent_result_spaces.append(devel_space)
                # since catkin_make_isolated doesn't provide a custom
                # environment to run tests this needs to source the devel space
                # and force a CMake run ro use the new environment
                with Scope('SUBSECTION', 'run tests'):
                    rc = call_build_tool(
                        args.build_tool,
                        args.rosdistro_name, args.workspace_root,
                        cmake_args=cmake_args,
                        force_cmake=args.build_tool == 'catkin_make_isolated',
                        make_args=make_args, args=additional_args,
                        parent_result_spaces=parent_result_spaces, env=env,
                        colcon_verb='test')
    finally:
        if args.clean_after:
            clean_workspace(args.workspace_root)

    return rc