|  | 
| 13 | 13 | # limitations under the License. | 
| 14 | 14 | 
 | 
| 15 | 15 | import os | 
|  | 16 | +import json | 
|  | 17 | +import subprocess | 
| 16 | 18 | import sys | 
|  | 19 | +import shutil | 
|  | 20 | +from os.path import join | 
|  | 21 | + | 
|  | 22 | +from platformio.public import PlatformBase, to_unix_path | 
|  | 23 | +from platformio.proc import get_pythonexe_path | 
|  | 24 | +from platformio.project.config import ProjectConfig | 
|  | 25 | +from platformio.package.manager.tool import ToolPackageManager | 
| 17 | 26 | 
 | 
| 18 |  | -from platformio.public import PlatformBase | 
| 19 | 27 | 
 | 
| 20 | 28 | IS_WINDOWS = sys.platform.startswith("win") | 
| 21 | 29 | # Set Platformio env var to use windows_amd64 for all windows architectures | 
| 22 | 30 | # only windows_amd64 native espressif toolchains are available | 
| 23 |  | -# needs platformio core >= 6.1.16b2 or pioarduino core 6.1.16+test | 
|  | 31 | +# needs platformio/pioarduino core >= 6.1.17 | 
| 24 | 32 | if IS_WINDOWS: | 
| 25 | 33 |     os.environ["PLATFORMIO_SYSTEM_TYPE"] = "windows_amd64" | 
| 26 | 34 | 
 | 
| 27 |  | -class Espressif8266Platform(PlatformBase): | 
|  | 35 | +python_exe = get_pythonexe_path() | 
|  | 36 | +pm = ToolPackageManager() | 
| 28 | 37 | 
 | 
|  | 38 | +class Espressif8266Platform(PlatformBase): | 
| 29 | 39 |     def configure_default_packages(self, variables, targets): | 
| 30 |  | -        framework = variables.get("pioframework", []) | 
| 31 |  | -        if "buildfs" in targets: | 
| 32 |  | -            self.packages['tool-mklittlefs']['optional'] = False | 
|  | 40 | +        if not variables.get("board"): | 
|  | 41 | +            return super().configure_default_packages(variables, targets) | 
|  | 42 | + | 
|  | 43 | +        frameworks = variables.get("pioframework", []) | 
|  | 44 | + | 
|  | 45 | +        def install_tool(TOOL, retry_count=0): | 
|  | 46 | +            self.packages[TOOL]["optional"] = False | 
|  | 47 | +            TOOL_PATH = os.path.join(ProjectConfig.get_instance().get("platformio", "packages_dir"), TOOL) | 
|  | 48 | +            TOOL_PACKAGE_PATH = os.path.join(TOOL_PATH, "package.json") | 
|  | 49 | +            TOOLS_PATH_DEFAULT = os.path.join(os.path.expanduser("~"), ".platformio") | 
|  | 50 | +            IDF_TOOLS = os.path.join(ProjectConfig.get_instance().get("platformio", "packages_dir"), "tl-install", "tools", "idf_tools.py") | 
|  | 51 | +            TOOLS_JSON_PATH = os.path.join(TOOL_PATH, "tools.json") | 
|  | 52 | +            TOOLS_PIO_PATH = os.path.join(TOOL_PATH, ".piopm") | 
|  | 53 | +            IDF_TOOLS_CMD = ( | 
|  | 54 | +                python_exe, | 
|  | 55 | +                IDF_TOOLS, | 
|  | 56 | +                "--quiet", | 
|  | 57 | +                "--non-interactive", | 
|  | 58 | +                "--tools-json", | 
|  | 59 | +                TOOLS_JSON_PATH, | 
|  | 60 | +                "install" | 
|  | 61 | +            ) | 
|  | 62 | + | 
|  | 63 | +            tl_flag = bool(os.path.exists(IDF_TOOLS)) | 
|  | 64 | +            json_flag = bool(os.path.exists(TOOLS_JSON_PATH)) | 
|  | 65 | +            pio_flag = bool(os.path.exists(TOOLS_PIO_PATH)) | 
|  | 66 | +            if tl_flag and json_flag: | 
|  | 67 | +                rc = subprocess.run(IDF_TOOLS_CMD).returncode | 
|  | 68 | +                if rc != 0: | 
|  | 69 | +                    sys.stderr.write("Error: Couldn't execute 'idf_tools.py install'\n") | 
|  | 70 | +                else: | 
|  | 71 | +                    tl_path = "file://" + join(TOOLS_PATH_DEFAULT, "tools", TOOL) | 
|  | 72 | +                    try: | 
|  | 73 | +                        shutil.copyfile(TOOL_PACKAGE_PATH, join(TOOLS_PATH_DEFAULT, "tools", TOOL, "package.json")) | 
|  | 74 | +                    except FileNotFoundError as e: | 
|  | 75 | +                        sys.stderr.write(f"Error copying tool package file: {e}\n") | 
|  | 76 | +                    if os.path.exists(TOOL_PATH) and os.path.isdir(TOOL_PATH): | 
|  | 77 | +                        try: | 
|  | 78 | +                            shutil.rmtree(TOOL_PATH) | 
|  | 79 | +                        except Exception as e: | 
|  | 80 | +                            print(f"Error while removing the tool folder: {e}") | 
|  | 81 | +                    pm.install(tl_path) | 
|  | 82 | +            # tool is already installed, just activate it | 
|  | 83 | +            if tl_flag and pio_flag and not json_flag: | 
|  | 84 | +                with open(TOOL_PACKAGE_PATH, "r") as file: | 
|  | 85 | +                    package_data = json.load(file) | 
|  | 86 | +                # check installed tool version against listed in platforms.json | 
|  | 87 | +                if "package-version" in self.packages[TOOL] \ | 
|  | 88 | +                   and "version" in package_data \ | 
|  | 89 | +                   and self.packages[TOOL]["package-version"] == package_data["version"]: | 
|  | 90 | +                    self.packages[TOOL]["version"] = TOOL_PATH | 
|  | 91 | +                    self.packages[TOOL]["optional"] = False | 
|  | 92 | +                elif "package-version" not in self.packages[TOOL]: | 
|  | 93 | +                    # No version check needed, just use the installed tool | 
|  | 94 | +                    self.packages[TOOL]["version"] = TOOL_PATH | 
|  | 95 | +                    self.packages[TOOL]["optional"] = False | 
|  | 96 | +                elif "version" not in package_data: | 
|  | 97 | +                    print(f"Warning: Cannot determine installed version for {TOOL}. Reinstalling...") | 
|  | 98 | +                else:  # Installed version does not match required version, deinstall existing and install needed | 
|  | 99 | +                    if os.path.exists(TOOL_PATH) and os.path.isdir(TOOL_PATH): | 
|  | 100 | +                        try: | 
|  | 101 | +                            shutil.rmtree(TOOL_PATH) | 
|  | 102 | +                        except Exception as e: | 
|  | 103 | +                            print(f"Error while removing the tool folder: {e}") | 
|  | 104 | +                    if retry_count >= 3:  # Limit to 3 retries | 
|  | 105 | +                        print(f"Failed to install {TOOL} after multiple attempts. Please check your network connection and try again manually.") | 
|  | 106 | +                        return | 
|  | 107 | +                    print(f"Wrong version for {TOOL}. Installing needed version...") | 
|  | 108 | +                    install_tool(TOOL, retry_count + 1) | 
|  | 109 | + | 
|  | 110 | +            return | 
|  | 111 | + | 
|  | 112 | +        # Installer only needed for setup, deactivate when installed | 
|  | 113 | +        if bool(os.path.exists(os.path.join(ProjectConfig.get_instance().get("platformio", "packages_dir"), "tl-install", "tools", "idf_tools.py"))): | 
|  | 114 | +            self.packages["tl-install"]["optional"] = True | 
|  | 115 | + | 
|  | 116 | +        # tool-scons needs to be installed but can be set inactive | 
|  | 117 | +        if bool(os.path.exists(os.path.join(ProjectConfig.get_instance().get("platformio", "packages_dir"), "tool-scons", "scons.py"))): | 
|  | 118 | +            self.packages["tool-scons"]["optional"] = True | 
|  | 119 | +        else: | 
|  | 120 | +            install_tool("tool-scons") | 
|  | 121 | + | 
|  | 122 | +        self.packages["framework-arduinoespressif8266"]["optional"] = False | 
|  | 123 | +        install_tool("toolchain-xtensa") | 
|  | 124 | + | 
|  | 125 | +        CHECK_PACKAGES = [ | 
|  | 126 | +            "tool-cppcheck", | 
|  | 127 | +            "tool-clangtidy", | 
|  | 128 | +            "tool-pvs-studio" | 
|  | 129 | +        ] | 
|  | 130 | +        # Install check tool listed in pio entry "check_tool" | 
|  | 131 | +        if variables.get("check_tool") is not None: | 
|  | 132 | +            for package in CHECK_PACKAGES: | 
|  | 133 | +                for check_tool in variables.get("check_tool", ""): | 
|  | 134 | +                    if check_tool in package: | 
|  | 135 | +                        install_tool(package) | 
|  | 136 | + | 
|  | 137 | +        if "buildfs" or "uploadfs" or "downloadfs" in targets: | 
|  | 138 | +            filesystem = variables.get("board_build.filesystem", "littlefs") | 
|  | 139 | +            if filesystem == "littlefs": | 
|  | 140 | +                install_tool("tool-mklittlefs") | 
|  | 141 | +            elif filesystem == "spiffs": | 
|  | 142 | +                install_tool("tool-mkspiffs") | 
|  | 143 | + | 
| 33 | 144 |         return super().configure_default_packages(variables, targets) | 
| 34 | 145 | 
 | 
| 35 | 146 |     def get_boards(self, id_=None): | 
|  | 
0 commit comments