Skip to content

copy_sdk_python_binding

Pre-launch to copy SpeedTree Python Binding Script.

SpeedtreeStartupScript

Bases: PreLaunchHook

Copy Python Binding Folder from SpeedTree Pipeline SDK to the sdk folder, and so that the addon can get the correct PYTHONPATH to run the script.

Source code in client/ayon_speedtree/hooks/copy_sdk_python_binding.py
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
class SpeedtreeStartupScript(PreLaunchHook):
    """Copy Python Binding Folder from SpeedTree Pipeline SDK to
    the sdk folder, and so that the addon can get the correct
    PYTHONPATH to run the script.
    """
    app_groups = {"speedtree"}
    launch_types = {LaunchTypes.local}

    def _get_version(self, sdk_folder: pathlib.Path):
        site.addsitedir(pathlib.Path(sdk_folder).as_posix())
        import speedtree.SpeedTree as SpeedTree

        return SpeedTree.__version__

    def _sync_sdk_folder_by_perforce(self, sdk_folder: str):
        try:
            import ayon_perforce.api as perforce_api
            perforce_api.sync(sdk_folder)
            self.log.debug(
                f"Sync the sdk folder:{sdk_folder} to Perforce."
            )

        except ImportError as err:
            self.log.debug(f"Skip syncing folder to perforce as {err}")

    def _force_copy_files(self, src: pathlib.Path, dst: pathlib.Path):
        if dst.is_dir():
            try:
                shutil.copytree(src, dst)
                return
            except FileExistsError as error:
                if (
                    "Cannot create a file when that file already exists:"
                    in str(error)
                ):
                    for sub_path in src.iterdir():
                        self._force_copy_files(sub_path, dst / sub_path.name)

                    return

                raise

        try:
            shutil.copy(src, dst)
        except PermissionError:
            os.chmod(str(dst), stat.S_IWRITE)
            shutil.copy(src, dst)

    def execute(self):
        speedtree_settings = self.data["project_settings"]["speedtree"]
        sdk_folder = os.path.normpath(
            speedtree_settings["sdk_directory"]
        )
        if not sdk_folder and not os.path.exists(sdk_folder):
            raise RuntimeError(
                "Directory not found. Fail to copy the "
                "SDK python binding folder.")

        version = self._get_version(sdk_folder)
        dst_folder = pathlib.Path(os.path.join(
            SPTREE_ADDON_ROOT, "api", "sdk", "speedtree", version
        ))
        self._sync_sdk_folder_by_perforce(sdk_folder)
        python_env = self.launch_context.env["PYTHONPATH"]
        paths = python_env.split(os.pathsep)
        paths.append(dst_folder.as_posix())
        self.launch_context.env["PYTHONPATH"] = os.pathsep.join(paths)
        if dst_folder.exists():
            filecmp.clear_cache()
            if not filecmp.cmp(sdk_folder, dst_folder, shallow=False):
                self.log.info(
                    (
                        "Local SpeedTree SDK folder already exists:\n"
                        f"- {dst_folder}"
                    )
                )
                return

            self.log.info(
                (
                    "Local SpeedTree SDK folder exists but is out of date:\n"
                    f"- {dst_folder}\n"
                    "Force updating..."
                )
            )
            self._force_copy_files(sdk_folder, dst_folder)
            return

        shutil.copytree(sdk_folder, dst_folder)
        self.log.info(
            "SpeedTree Python binding folder "
            f"copied from {sdk_folder} -> {dst_folder}"
        )