def test_from_url_raises_if_dest_dir_contains_program(self, fs): fs_root = pathlib.Path(fs, "foo") make_mbed_program_files(fs_root) url = "https://valid" with self.assertRaises(ExistingProgram): MbedProgram.from_url(url, fs_root)
def test_from_new_local_dir_raises_if_path_is_existing_program(self, fs): program_root = pathlib.Path(fs, "programfoo") program_root.mkdir() (program_root / ".mbed").touch() with self.assertRaises(ExistingProgram): MbedProgram.from_new(program_root)
def test_from_existing_raises_if_no_mbed_os_dir_found_and_check_mbed_os_is_true( self, fs): fs_root = pathlib.Path(fs, "foo") make_mbed_program_files(fs_root) with self.assertRaises(MbedOSNotFound): MbedProgram.from_existing(fs_root, check_mbed_os=True)
def test_from_url_raises_if_check_mbed_os_is_true_and_mbed_os_dir_nonexistent(self, mock_clone, fs): fs_root = pathlib.Path(fs, "foo") url = "https://validrepo.com" mock_clone.side_effect = lambda *args: make_mbed_program_files(fs_root) with self.assertRaises(MbedOSNotFound): MbedProgram.from_url(url, fs_root, check_mbed_os=True)
def test_from_existing_raises_if_path_is_not_a_program(self, fs): fs_root = pathlib.Path(fs, "foo") fs_root.mkdir() program_root = fs_root / "programfoo" with self.assertRaises(ProgramNotFound): MbedProgram.from_existing(program_root)
def test_from_existing_raises_if_path_is_not_a_program(self, tmp_path): fs_root = pathlib.Path(tmp_path, "foo") fs_root.mkdir() program_root = fs_root / "programfoo" with pytest.raises(ProgramNotFound): MbedProgram.from_existing(program_root, DEFAULT_BUILD_SUBDIR)
def configure(toolchain: str, mbed_target: str, program_path: str, mbed_os_path: str) -> None: """Exports a mbed_config.cmake file to build directory in the program root. The parameters set in the CMake file will be dependent on the combination of toolchain and Mbed target provided and these can then control which parts of Mbed OS are included in the build. This command will create the .mbedbuild directory at the program root if it doesn't exist. Args: toolchain: the toolchain you are using (eg. GCC_ARM, ARM) mbed_target: the target you are building for (eg. K64F) program_path: the path to the local Mbed program mbed_os_path: the path to the local Mbed OS directory """ cmake_build_subdir = pathlib.Path(mbed_target.upper(), "develop", toolchain.upper()) if mbed_os_path is None: program = MbedProgram.from_existing(pathlib.Path(program_path), cmake_build_subdir) else: program = MbedProgram.from_existing(pathlib.Path(program_path), cmake_build_subdir, pathlib.Path(mbed_os_path)) mbed_target = mbed_target.upper() output_path = generate_config(mbed_target, toolchain, program) click.echo( f"mbed_config.cmake has been generated and written to '{str(output_path.resolve())}'" )
def test_from_new_local_dir_raises_if_path_is_existing_program( self, tmp_path): program_root = pathlib.Path(tmp_path, "programfoo") program_root.mkdir() (program_root / "mbed-os.lib").touch() with pytest.raises(ExistingProgram): MbedProgram.from_new(program_root)
def test_from_existing_raises_if_program_files_missing(self, fs): fs_root = pathlib.Path(fs, "foo") fs_root.mkdir() (fs_root / ".mbed").touch() program_root = fs_root with self.assertRaises(ProgramNotFound): MbedProgram.from_existing(program_root)
def test_from_url_raises_if_cloned_repo_is_not_program(self, mock_repo, fs): fs_root = pathlib.Path(fs, "foo") fs_root.mkdir() url = "https://validrepo.com" mock_repo.side_effect = lambda url, dst_dir: dst_dir.mkdir() with self.assertRaises(ProgramNotFound): MbedProgram.from_url(url, fs_root / "corrupt-prog")
def test_from_existing_raises_if_no_mbed_os_dir_found_and_check_mbed_os_is_true( self, tmp_path): fs_root = pathlib.Path(tmp_path, "foo") make_mbed_program_files(fs_root) with pytest.raises(MbedOSNotFound): MbedProgram.from_existing(fs_root, DEFAULT_BUILD_SUBDIR, check_mbed_os=True)
def test_checks_for_unresolved_libraries(self, fs): root = pathlib.Path(fs, "root") make_mbed_lib_reference(root, resolved=True, ref_url="https://blah") make_mbed_lib_reference(root, name="my-unresolved-lib.lib", resolved=False, ref_url="https://blah") mbed_os_root = root / "mbed-os" mbed_os_root.mkdir() program = MbedProgram( None, MbedProgramFiles(None, pathlib.Path(root / ".mbed"), None), MbedOS(mbed_os_root, None) ) self.assertTrue(program.has_unresolved_libraries())
def test_lists_all_known_libraries(self, fs): root = pathlib.Path(fs, "root") lib_ref = make_mbed_lib_reference(root, resolved=True, ref_url="https://blah") lib_ref_unresolved = make_mbed_lib_reference( root, name="my-unresolved-lib.lib", resolved=False, ref_url="https://blah" ) mbed_os_root = root / "mbed-os" mbed_os_root.mkdir() program = MbedProgram( None, MbedProgramFiles(None, pathlib.Path(root, ".mbed"), None), MbedOS(mbed_os_root, None) ) libs = program.list_known_library_dependencies() self.assertEqual(str(lib_ref_unresolved), str(libs[0])) self.assertEqual(str(lib_ref), str(libs[1]))
def test_from_new_local_dir_generates_valid_program_creating_directory(self, fs): fs_root = pathlib.Path(fs, "foo") fs_root.mkdir() program_root = fs_root / "programfoo" program = MbedProgram.from_new(program_root) self.assertEqual(program.files, MbedProgramFiles.from_existing(program_root))
def test_from_url_returns_valid_program(self, mock_clone, fs): fs_root = pathlib.Path(fs, "foo") url = "https://valid" mock_clone.side_effect = lambda *args: make_mbed_program_files(fs_root) program = MbedProgram.from_url(url, fs_root, False) self.assertEqual(program.files, MbedProgramFiles.from_existing(fs_root)) mock_clone.assert_called_once_with(url, fs_root)
def test_checks_for_unresolved_libraries(self, fs): root = pathlib.Path(fs, "root").absolute().resolve() make_mbed_program_files(root) make_mbed_lib_reference(root, resolved=True, ref_url="https://blah") make_mbed_lib_reference(root, name="my-unresolved-lib.lib", resolved=False, ref_url="https://blah") program = MbedProgram.from_existing(root, check_mbed_os=False) self.assertTrue(program.has_unresolved_libraries())
def test_from_existing_returns_valid_program(self, fs): fs_root = pathlib.Path(fs, "foo") make_mbed_program_files(fs_root) make_mbed_os_files(fs_root / "mbed-os") program = MbedProgram.from_existing(fs_root, DEFAULT_BUILD_SUBDIR) self.assertTrue(program.files.app_config_file.exists()) self.assertTrue(program.mbed_os.root.exists())
def test_from_new_local_dir_generates_valid_program(self, mock_init, fs): fs_root = pathlib.Path(fs, "foo") fs_root.mkdir() program_root = fs_root / "programfoo" program = MbedProgram.from_new(program_root) self.assertEqual(program.files, MbedProgramFiles.from_existing(program_root)) self.assertEqual(program.repo, mock_init.return_value) mock_init.assert_called_once_with(program_root)
def test_from_existing_returns_valid_program(self, mock_repo, fs): fs_root = pathlib.Path(fs, "foo") make_mbed_program_files(fs_root) make_mbed_os_files(fs_root / "mbed-os") program = MbedProgram.from_existing(fs_root) self.assertTrue(program.files.app_config_file.exists()) self.assertTrue(program.mbed_os.root.exists()) self.assertIsNotNone(program.repo)
def configure(toolchain: str, mbed_target: str, profile: str, program_path: str, mbed_os_path: str, output_dir: str, custom_targets_json: str, app_config: str) -> None: """Exports a mbed_config.cmake file to build directory in the program root. The parameters set in the CMake file will be dependent on the combination of toolchain and Mbed target provided and these can then control which parts of Mbed OS are included in the build. This command will create the .mbedbuild directory at the program root if it doesn't exist. Args: custom_targets_json: the path to custom_targets.json toolchain: the toolchain you are using (eg. GCC_ARM, ARM) mbed_target: the target you are building for (eg. K64F) profile: The Mbed build profile (debug, develop or release). program_path: the path to the local Mbed program mbed_os_path: the path to the local Mbed OS directory output_dir: the path to the output directory app_config: the path to the application configuration file """ cmake_build_subdir = pathlib.Path(mbed_target.upper(), profile.lower(), toolchain.upper()) if mbed_os_path is None: program = MbedProgram.from_existing(pathlib.Path(program_path), cmake_build_subdir) else: program = MbedProgram.from_existing(pathlib.Path(program_path), cmake_build_subdir, pathlib.Path(mbed_os_path)) if custom_targets_json is not None: program.files.custom_targets_json = pathlib.Path(custom_targets_json) if output_dir is not None: program.files.cmake_build_dir = pathlib.Path(output_dir) if app_config is not None: program.files.app_config_file = pathlib.Path(app_config) mbed_target = mbed_target.upper() _, output_path = generate_config(mbed_target, toolchain, program) click.echo( f"mbed_config.cmake has been generated and written to '{str(output_path.resolve())}'" )
def test_from_existing_with_mbed_os_path_returns_valid_program(self, fs): fs_root = pathlib.Path(fs, "foo") mbed_os_path = fs_root / "extern/mbed-os" mbed_os_path.mkdir(parents=True) make_mbed_program_files(fs_root) make_mbed_os_files(mbed_os_path) program = MbedProgram.from_existing(fs_root, DEFAULT_BUILD_SUBDIR, mbed_os_path) self.assertTrue(program.files.app_config_file.exists()) self.assertTrue(program.mbed_os.root.exists())
def program(tmp_path): prog = MbedProgram.from_new(tmp_path / "test-prog") # Overwrite the default mbed_app.json so it doesn't mess with our test env prog.files.app_config_file.write_text(json.dumps({"": ""})) # Create program mbed-os directory and fake targets.json prog.mbed_os.root.mkdir(parents=True) prog.mbed_os.targets_json_file.parent.mkdir(exist_ok=True, parents=True) prog.mbed_os.targets_json_file.write_text( json.dumps({target: TARGET_DATA for target in TARGETS})) return prog
def test_lists_all_known_libraries(self, fs): root = pathlib.Path(fs, "root").absolute().resolve() make_mbed_program_files(root) lib_ref = make_mbed_lib_reference(root, resolved=True, ref_url="https://blah") lib_ref_unresolved = make_mbed_lib_reference( root, name="my-unresolved-lib.lib", resolved=False, ref_url="https://blah" ) program = MbedProgram.from_existing(root, check_mbed_os=False) libs = program.list_known_library_dependencies() self.assertEqual(str(lib_ref_unresolved), str(libs[1])) self.assertEqual(str(lib_ref), str(libs[2]))
def test_from_new_local_dir_generates_valid_program_creating_directory_in_cwd(self, fs): old_cwd = os.getcwd() try: fs_root = pathlib.Path(fs, "foo") fs_root.mkdir() os.chdir(fs_root) program_root = pathlib.Path("programfoo") program = MbedProgram.from_new(program_root) self.assertEqual(program.files, MbedProgramFiles.from_existing(program_root)) finally: os.chdir(old_cwd)
def program_in_mbed_os_subdir(tmp_path): mbed_os_path = tmp_path / "mbed-os" targets_json = mbed_os_path / "targets" / "targets.json" program_root = mbed_os_path / "test-prog" build_subdir = program_root / "__build" / "k64f" program_root.mkdir(parents=True, exist_ok=True) # Create program mbed-os directory and fake targets.json targets_json.parent.mkdir(exist_ok=True, parents=True) targets_json.write_text( json.dumps({target: TARGET_DATA for target in TARGETS})) return MbedProgram.from_existing(program_root, build_subdir, mbed_os_path=mbed_os_path)
def assemble_config(mbed_target: str, mbed_program_directory: Path) -> Config: """Assemble Config for given target and program directory. The structure and configuration of MbedOS requires us to do multiple passes over configuration files, as each pass might affect which configuration files should be included in the final configuration. """ target_source = Source.from_target(mbed_target, mbed_program_directory) mbed_lib_files = find_files("mbed_lib.json", mbed_program_directory) mbed_program = MbedProgram.from_existing(mbed_program_directory) mbed_app_file = mbed_program.files.app_config_file return _assemble_config_from_sources_and_lib_files(target_source, mbed_lib_files, mbed_app_file)
def build(program_path: str, build_type: str, toolchain: str = "", mbed_target: str = "", clean: bool = False) -> None: """Configure and build an Mbed project using CMake and Ninja. If the project has already been configured and contains '.mbedbuild/mbed_config.cmake', this command will skip the Mbed configuration step and invoke CMake. If the CMake configuration step has already been run previously (i.e a CMake build tree exists), then just try to build the project immediately using Ninja. Args: program_path: Path to the Mbed project. build_type: The Mbed build profile (debug, develop or release). toolchain: The toolchain to use for the build. mbed_target: The name of the Mbed target to build for. clean: Force regeneration of config and build system before building. """ program = MbedProgram.from_existing(pathlib.Path(program_path)) mbed_config_file = program.files.cmake_config_file if not mbed_config_file.exists() or clean: click.echo("Generating Mbed config...") if not toolchain: raise click.UsageError( "--toolchain argument is required when generating Mbed config!" ) if not mbed_target: raise click.UsageError( "--mbed-target argument is required when generating Mbed config!" ) generate_config(mbed_target.upper(), toolchain, program) build_tree = program.files.cmake_build_dir if not build_tree.exists() or clean: generate_build_system(program.root, build_tree, build_type) build_project(build_tree)
def build( program_path: str, profile: str, toolchain: str = "", mbed_target: str = "", clean: bool = False, flash: bool = False, hex_file: bool = False, sterm: bool = False, baudrate: int = 9600, mbed_os_path: str = None, custom_targets_json: str = None, ) -> None: """Configure and build an Mbed project using CMake and Ninja. If the CMake configuration step has already been run previously (i.e a CMake build tree exists), then just try to build the project immediately using Ninja. Args: program_path: Path to the Mbed project. mbed_os_path: The path to the local Mbed OS directory. profile: The Mbed build profile (debug, develop or release). custom_targets_json: Path to custom_targets.json. toolchain: The toolchain to use for the build. mbed_target: The name of the Mbed target to build for. clean: Perform a clean build. flash: Flash the binary onto a device. hex_file: Use hex file, this option should be used with '-f/--flash' option. sterm: Open a serial terminal to the connected target. baudrate: Change the serial baud rate (ignored unless --sterm is also given). """ _validate_target_and_toolchain_args(mbed_target, toolchain) mbed_target, target_id = _get_target_id(mbed_target) cmake_build_subdir = pathlib.Path(mbed_target.upper(), profile.lower(), toolchain.upper()) if mbed_os_path is None: program = MbedProgram.from_existing(pathlib.Path(program_path), cmake_build_subdir) else: program = MbedProgram.from_existing(pathlib.Path(program_path), cmake_build_subdir, pathlib.Path(mbed_os_path)) build_tree = program.files.cmake_build_dir if clean and build_tree.exists(): shutil.rmtree(build_tree) click.echo("Configuring project and generating build system...") if custom_targets_json is not None: program.files.custom_targets_json = pathlib.Path(custom_targets_json) generate_config(mbed_target.upper(), toolchain, program) generate_build_system(program.root, build_tree, profile) click.echo("Building Mbed project...") build_project(build_tree) if flash or sterm: if target_id is not None or sterm: devices = [find_connected_device(mbed_target, target_id)] else: devices = find_all_connected_devices(mbed_target) if flash: for dev in devices: flashed_path = flash_binary(dev.mount_points[0].resolve(), program.root, build_tree, mbed_target, hex_file) click.echo( f"Copied {str(flashed_path.resolve())} to {len(devices)} device(s)." ) elif hex_file: click.echo( "'--hex-file' option should be used with '-f/--flash' option") if sterm: dev = devices[0] if dev.serial_port is None: raise click.ClickException( f"The connected device {dev.mbed_board.board_name} does not have an associated serial port." " Reconnect the device and try again.") terminal.run(dev.serial_port, baudrate)
def test_from_existing_raises_if_no_repo_found(self, fs): fs_root = pathlib.Path(fs, "foo") make_mbed_program_files(fs_root) with self.assertRaises(VersionControlError): MbedProgram.from_existing(fs_root)
def test_checkout_libraries(self, mock_lib_refs): program = MbedProgram(None, MbedProgramFiles(None, pathlib.Path(), None), MbedOS(pathlib.Path(), None)) program.checkout_libraries() program.lib_references.checkout.assert_called_once()