embuild 0.33.1

A build support library for embedded Rust
Documentation
# A small PlatformIO integration script (autogenerated by cargo-pio) that provides the capability to patch
# PlatformIO packages (or the platform itself) before the build is triggered
#
# How to use:
# Insert/update the following line in one of platformio.ini's environments:
#     extra_scripts = pre:platformio.patch.py
# Specify a newline-separated list of patches to apply:
#     patches = <pio-package-directory1>@<patch-file1> \n <pio-package-directory2>@<patch-file2>...
# ... where <patch-file-1>, <patch-file-2> etc. are expected to be placed in a 'patches/' folder of your project
#
# When <pio-package-directory> is equal to "__platform__", the platform itself will be patched

import os
import shutil

Import("env")

class Patch:
    def run(self, env):
        for (patch, patch_name, dir) in self.__patches_list(env):
            self.__patch(env, patch, patch_name, dir)

    def __patch(self, env, patch, patch_name, dir):
        patch_flag = os.path.join(dir, f"{patch_name}.applied")

        if not os.path.isfile(patch_flag):
            # In recent PlatformIO, framework_espidf is no longer a true GIT repository
            # (i.e. it does not contain a .git subfolder)
            # As a result, "git apply" does not really work
            #
            # One workaround would've been to use `patch` instead of `git apply`, 
            # however `patch` does not seem to be available on Windows out of the box
            #
            # Therefore, instead we do a nasty hack here: we check if `dir` 
            # contains a `.git` folder, and if not we create it using "git init"
            #
            # Once the patch is applied, we remove the `.git` folder
            git_dir = os.path.join(dir, ".git")
            git_dir_exists = True

            if not os.path.exists(git_dir):
                if env.Execute("git init", chdir = dir):
                    env.Exit(1)
                git_dir_exists = False

            res = env.Execute(f"git apply {patch}", chdir = dir)

            if not git_dir_exists:
                shutil.rmtree(git_dir)

            if res:
                env.Exit(1)

            self.__touch(patch_flag)

    def __patches_list(self, env):
        patches_dir = os.path.join(env.subst("$PROJECT_DIR"), "patches")

        def get_patch(item):
            dir, patch = item.split("@", 1)

            package = dir.strip()
            if package == "__platform__":
                package_dir = env.PioPlatform().get_dir()
            else:
                package_dir = env.PioPlatform().get_package_dir(package)

            return (
                os.path.join(patches_dir, patch.strip()),
                patch.strip(),
                package_dir)

        return [get_patch(item) for item in env.GetProjectOption("patches", default = "").split("\n") if len(item.strip()) > 0]

    def __touch(self, path):
        os.open(path, os.O_CREAT | os.O_RDWR)

Patch().run(env)