예제 #1
0
    def test_performs_checkout_if_git_ref_exists(self, mock_init, mock_checkout, mock_clone, fs):
        fs_root = pathlib.Path(fs, "foo")
        lib = make_mbed_lib_reference(fs_root, ref_url="https://git#lajdhalk234", resolved=True)

        lib_refs = LibraryReferences(fs_root, ignore_paths=[fs_root / "mbed-os"])
        lib_refs.checkout(force=False)

        mock_checkout.assert_called_once_with(mock_init.return_value, lib.get_git_reference().ref, force=False)
예제 #2
0
    def test_does_not_perform_checkout_if_no_git_ref_exists(self, mock_init, mock_checkout, mock_clone, fs):
        fs_root = pathlib.Path(fs, "foo")
        make_mbed_lib_reference(fs_root, ref_url="https://git", resolved=True)

        lib_refs = LibraryReferences(fs_root, ignore_paths=[fs_root / "mbed-os"])
        lib_refs.checkout(force=False)

        mock_checkout.assert_not_called()
예제 #3
0
    def test_resolve_performs_checkout_if_git_ref_exists(self, mock_init, mock_checkout, mock_clone, fs):
        fs_root = pathlib.Path(fs, "foo")
        lib = make_mbed_lib_reference(fs_root, ref_url="https://git#lajdhalk234")
        mock_clone.side_effect = lambda url, dst_dir: dst_dir.mkdir()

        lib_refs = LibraryReferences(fs_root, ignore_paths=[fs_root / "mbed-os"])
        lib_refs.resolve()

        mock_checkout.assert_called_once_with(None, lib.get_git_reference().ref)
예제 #4
0
    def test_resolve_does_not_perform_checkout_if_no_git_ref_exists(self, mock_init, mock_checkout, mock_clone, fs):
        fs_root = pathlib.Path(fs, "foo")
        make_mbed_lib_reference(fs_root, ref_url="https://git")
        mock_clone.side_effect = lambda url, dst_dir: dst_dir.mkdir()

        lib_refs = LibraryReferences(fs_root, ignore_paths=[fs_root / "mbed-os"])
        lib_refs.resolve()

        mock_checkout.assert_not_called()
예제 #5
0
    def test_hydrates_top_level_library_references(self, mock_clone, fs):
        fs_root = pathlib.Path(fs, "foo")
        lib = make_mbed_lib_reference(fs_root, ref_url="https://git")
        mock_clone.side_effect = lambda url, dst_dir: dst_dir.mkdir()

        lib_refs = LibraryReferences(fs_root, ignore_paths=[fs_root / "mbed-os"])
        lib_refs.resolve()

        mock_clone.assert_called_once_with(lib.get_git_reference().repo_url, lib.source_code_path)
        self.assertTrue(lib.is_resolved())
예제 #6
0
    def __init__(self, repo: git_utils.git.Repo,
                 program_files: MbedProgramFiles, mbed_os: MbedOS) -> None:
        """Initialise the program attributes.

        Args:
            repo: The program's git repository.
            program_files: Object holding paths to a set of files that define an Mbed program.
            mbed_os: An instance of `MbedOS` holding paths to locations in the local copy of the Mbed OS source.
        """
        self.repo = repo
        self.files = program_files
        self.mbed_os = mbed_os
        self.lib_references = LibraryReferences(
            root=self.files.mbed_file.parent, ignore_paths=[self.mbed_os.root])
예제 #7
0
    def test_hydrates_recursive_dependencies(self, mock_clone, fs):
        fs_root = pathlib.Path(fs, "foo")
        lib = make_mbed_lib_reference(fs_root, ref_url="https://git")
        # Create a lib reference without touching the fs at this point, we want to mock the effects of a recursive
        # reference lookup and we need to assert the reference was resolved.
        lib2 = MbedLibReference(
            reference_file=(lib.source_code_path / "lib2.lib"), source_code_path=(lib.source_code_path / "lib2")
        )
        # Here we mock the effects of a recursive reference lookup. We create a new lib reference as a side effect of
        # the first call to the mock. Then we create the src dir, thus resolving the lib, on the second call.
        mock_clone.side_effect = lambda url, dst_dir: (
            make_mbed_lib_reference(pathlib.Path(dst_dir), name=lib2.reference_file.name, ref_url="https://valid2"),
            lib2.source_code_path.mkdir(),
        )

        lib_refs = LibraryReferences(fs_root, ignore_paths=[fs_root / "mbed-os"])
        lib_refs.resolve()

        self.assertTrue(lib.is_resolved())
        self.assertTrue(lib2.is_resolved())
예제 #8
0
class MbedProgram:
    """Represents an Mbed program.

    An `MbedProgram` consists of:
        * A git repository
        * A copy of, or reference to, `MbedOS`
        * A set of `MbedProgramFiles`
        * A collection of references to external libraries, defined in .lib files located in the program source tree
    """
    def __init__(self, repo: git_utils.git.Repo,
                 program_files: MbedProgramFiles, mbed_os: MbedOS) -> None:
        """Initialise the program attributes.

        Args:
            repo: The program's git repository.
            program_files: Object holding paths to a set of files that define an Mbed program.
            mbed_os: An instance of `MbedOS` holding paths to locations in the local copy of the Mbed OS source.
        """
        self.repo = repo
        self.files = program_files
        self.mbed_os = mbed_os
        self.lib_references = LibraryReferences(
            root=self.files.mbed_file.parent, ignore_paths=[self.mbed_os.root])

    @classmethod
    def from_url(cls,
                 url: str,
                 dst_path: Path,
                 check_mbed_os: bool = True) -> "MbedProgram":
        """Fetch an Mbed program from a remote URL.

        Args:
            url: URL of the remote program repository.
            dst_path: Destination path for the cloned program.

        Raises:
            ExistingProgram: `dst_path` already contains an Mbed program.
        """
        if _tree_contains_program(dst_path):
            raise ExistingProgram(
                f"The destination path '{dst_path}' already contains an Mbed program. Please set the destination path "
                "to an empty directory.")
        logger.info(f"Cloning Mbed program from URL '{url}'.")
        repo = git_utils.clone(url, dst_path)

        try:
            program_files = MbedProgramFiles.from_existing(dst_path)
        except ValueError as e:
            raise ProgramNotFound(
                f"This repository does not contain a valid Mbed program at the top level. {e} "
                "Cloned programs must contain an mbed-os.lib file containing the URL to the Mbed OS repository. It is "
                "possible you have cloned a repository containing multiple mbed-programs. If this is the case, you "
                "should cd to a directory containing a program before performing any other operations."
            )

        try:
            mbed_os = MbedOS.from_existing(dst_path / MBED_OS_DIR_NAME,
                                           check_mbed_os)
        except ValueError as mbed_err:
            raise MbedOSNotFound(f"{mbed_err}")

        return cls(repo, program_files, mbed_os)

    @classmethod
    def from_new(cls, dir_path: Path) -> "MbedProgram":
        """Create an MbedProgram from an empty directory.

        Creates the directory if it doesn't exist.

        Args:
            dir_path: Directory in which to create the program.

        Raises:
            ExistingProgram: An existing program was found in the path.
        """
        if _tree_contains_program(dir_path):
            raise ExistingProgram(
                f"An existing Mbed program was found in the directory tree {dir_path}. It is not possible to nest Mbed "
                "programs. Please ensure there is no .mbed file in the cwd hierarchy."
            )

        logger.info(f"Creating Mbed program at path '{dir_path.resolve()}'")
        dir_path.mkdir(exist_ok=True)
        program_files = MbedProgramFiles.from_new(dir_path)
        logger.info(
            f"Creating git repository for the Mbed program '{dir_path}'")
        repo = git_utils.init(dir_path)
        mbed_os = MbedOS.from_new(dir_path / MBED_OS_DIR_NAME)
        return cls(repo, program_files, mbed_os)

    @classmethod
    def from_existing(cls,
                      dir_path: Path,
                      check_mbed_os: bool = True) -> "MbedProgram":
        """Create an MbedProgram from an existing program directory.

        Args:
            dir_path: Directory containing an Mbed program.
            check_mbed_os: If True causes an exception to be raised if the Mbed OS source directory does not
                           exist.

        Raises:
            ProgramNotFound: An existing program was not found in the path.
        """
        program_root = _find_program_root(dir_path)
        logger.info(f"Found existing Mbed program at path '{program_root}'")
        try:
            program = MbedProgramFiles.from_existing(program_root)
        except ValueError as program_files_err:
            raise ProgramNotFound(
                f"{dir_path} doesn't look like a path to a valid program. {program_files_err}"
            )

        repo = git_utils.get_repo(program_root)
        try:
            mbed_os = MbedOS.from_existing(program_root / MBED_OS_DIR_NAME,
                                           check_mbed_os)
        except ValueError as mbed_os_err:
            raise MbedOSNotFound(
                f"Mbed OS was not found due to the following error: {mbed_os_err}"
                "\nYou may need to resolve the mbed-os.lib reference. You can do this by performing a `checkout`."
            )

        return cls(repo, program, mbed_os)

    def resolve_libraries(self) -> None:
        """Resolve all external dependencies defined in .lib files."""
        self.lib_references.resolve()

    def checkout_libraries(self, force: bool = False) -> None:
        """Check out all resolved libraries to revisions specified in .lib files."""
        self.lib_references.checkout(force)

    def list_known_library_dependencies(self) -> List[MbedLibReference]:
        """Returns a list of all known library dependencies."""
        return [lib for lib in self.lib_references.iter_all()]

    def has_unresolved_libraries(self) -> bool:
        """Checks if any unresolved library dependencies exist in the program tree."""
        return bool(list(self.lib_references.iter_unresolved()))