[core] Update PIO builders to new structure

This commit is contained in:
Kuba Szczodrzyński
2023-02-26 22:04:18 +01:00
parent 8bbc7e13fb
commit 3413d70210
40 changed files with 814 additions and 769 deletions

View File

@@ -1,18 +1,16 @@
# Copyright (c) Kuba Szczodrzyński 2022-04-20.
import importlib
import json
import platform
import sys
from os import system
from os.path import dirname, join
from os.path import dirname
from typing import Dict
import click
from platformio.debug.config.base import DebugConfigBase
from platformio.debug.exception import DebugInvalidOptionsError
from platformio.package.exception import MissingPackageManifestError
from platformio.package.manager.base import BasePackageManager
from platformio.package.meta import PackageItem, PackageSpec
from platformio.package.meta import PackageItem
from platformio.platform.base import PlatformBase
from platformio.platform.board import PlatformBoardConfig
from semantic_version import SimpleSpec, Version
@@ -75,103 +73,61 @@ if dirname(__file__) in sys.path:
# Let ltchiptool know about LT's location
ltchiptool.lt_set_path(dirname(__file__))
libretuya_packages = None
manifest_default = {"version": "0.0.0", "description": "", "keywords": []}
def load_manifest(self, src):
try:
return BasePackageManager._load_manifest(self, src)
except MissingPackageManifestError:
# ignore all exceptions
pass
# get the installation temporary path
path = src.path if isinstance(src, PackageItem) else src
# raise the exception if this package is not from libretuya
if (
not hasattr(self, "spec_map")
or path not in self.spec_map
or not libretuya_packages
):
raise MissingPackageManifestError(", ".join(self.manifest_names))
# get the saved spec
spec: PackageSpec = self.spec_map[path]
# read package data from platform.json
manifest: dict = libretuya_packages[spec.name]
# find additional manifest info
manifest = manifest.get("manifest", manifest_default)
# extract tag version
url = getattr(spec, "url", None) or getattr(spec, "uri", None) or ""
if "#" in url:
manifest["version"] = url.rpartition("#")[2].lstrip("v")
# put info from spec
manifest.update(
{
"name": spec.name,
"repository": {
"type": "git",
"url": url,
},
}
)
# save in cache
cache_key = "load_manifest-%s" % path
self.memcache_set(cache_key, manifest)
# result = ManifestParserFactory.new(json.dumps(manifest), ManifestFileType.PACKAGE_JSON).as_dict()
with open(join(path, self.manifest_names[0]), "w") as f:
json.dump(manifest, f)
return manifest
def find_pkg_root(self, path: str, spec: PackageSpec):
try:
return BasePackageManager._find_pkg_root(self, path, spec)
except MissingPackageManifestError as e:
# raise the exception if this package is not from libretuya
if not libretuya_packages or spec.name not in libretuya_packages:
raise e
# save the spec for later
if not hasattr(self, "spec_map"):
self.spec_map = {}
self.spec_map[path] = spec
return path
class LibretuyaPlatform(PlatformBase):
boards_base: Dict[str, dict] = {}
custom_opts: Dict[str, object] = {}
custom_opts: Dict[str, object] = None
versions: Dict[str, str] = None
def __init__(self, manifest_path):
super().__init__(manifest_path)
self.custom_opts = {}
self.versions = {}
def configure_default_packages(self, options, targets):
# patch find_pkg root to ignore missing manifests and save PackageSpec
if not hasattr(BasePackageManager, "_find_pkg_root"):
BasePackageManager._find_pkg_root = BasePackageManager.find_pkg_root
BasePackageManager.find_pkg_root = find_pkg_root
# patch load_manifest to generate manifests from PackageSpec
if not hasattr(BasePackageManager, "_load_manifest"):
BasePackageManager._load_manifest = BasePackageManager.load_manifest
BasePackageManager.load_manifest = load_manifest
from ltchiptool.util.dict import RecursiveDict
pioframework = options.get("pioframework")
if not pioframework:
return
framework = pioframework[0]
framework: str = pioframework[0]
# allow using "arduino" as framework
if framework == "arduino":
board = self.get_boards(options.get("board"))
frameworks = board.get("frameworks")
framework = next(fw for fw in frameworks if framework in fw)
options.get("pioframework")[0] = framework
# save custom options from env
self.custom_opts = RecursiveDict()
for key, value in options.items():
if not key.startswith("custom_"):
continue
self.custom_opts[key[7:]] = value
# update framework names to their new values since v1.0.0
if framework.endswith("-sdk"):
click.secho(
f"Framework '{framework}' is now named 'base'. "
"Update your platformio.ini to use the new name, then try again.",
fg="red",
)
exit(1)
if framework.endswith("-arduino"):
click.secho(
f"Framework '{framework}' is now named 'arduino'. "
"Update your platformio.ini to use the new name, then try again.",
fg="red",
)
exit(1)
options.get("pioframework")[0] = framework
# make ArduinoCore-API required
if "arduino" in framework:
if framework == "arduino":
self.packages["framework-arduino-api"]["optional"] = False
framework_obj = self.frameworks[framework]
if "package" in framework_obj:
package_obj = self.packages[framework_obj["package"]]
else:
package_obj = {}
# get framework SDK package
board = self.get_boards(options.get("board"))
package = board.get("package")
package_obj = self.packages.get(package, {})
# mark framework SDK as required
package_obj["optional"] = False
# get user-chosen versions of libraries/toolchains
versions: RecursiveDict = self.custom("versions") or {}
# set specific compiler versions
if "toolchains" in package_obj:
@@ -182,49 +138,75 @@ class LibretuyaPlatform(PlatformBase):
(toolchain, version) = toolchains["arm64"].split("@")
else:
(toolchain, version) = toolchains["x86_64"].split("@")
version = versions.get("toolchain") or version
self.packages[f"toolchain-{toolchain}"]["version"] = version
# mark framework SDK as required
package_obj["optional"] = False
# gather library dependencies
libraries = package_obj["libraries"] if "libraries" in package_obj else {}
for name, package in self.packages.items():
pkg_versions = {}
for package in self.packages.values():
if "optional" in package and package["optional"]:
continue
if "libraries" not in package:
continue
libraries.update(package["libraries"])
for name, lib_versions in package["libraries"].items():
package = f"library-{name}"
if name in versions and versions[name] in lib_versions:
pkg_versions[package] = lib_versions[versions[name]]
continue
if "default" in lib_versions:
pkg_versions[package] = lib_versions["default"]
# use appropriate vendor library versions
packages_new = {}
for name, package in self.packages.items():
if not name.startswith("library-"):
# gather custom versions of other libraries
for name, version in versions.items():
if name == "toolchain":
continue
name = name[8:] # strip "library-"
if name not in libraries:
name = name.replace("_", "-")
version = version.lstrip("v")
# find the package by "library-xxx", "framework-xxx" or "tool-xxx"
package = f"library-{name}"
if package not in self.packages:
package = f"framework-{name}"
if package not in self.packages:
package = f"tool-{name}"
if package not in self.packages:
click.secho(
f"Library '{name}' couldn't be found. "
f"Remove 'custom_versions.{name}' from platformio.ini and try again.",
fg="red",
)
exit(1)
if package in pkg_versions:
# skip already added libs
continue
lib_version = libraries[name][-1] # get latest version tag
package = dict(**package) # clone the base package
package["version"] = (
package["base_url"] + "#" + lib_version
) # use the specific version
package["optional"] = False # make it required
lib_version = lib_version.lstrip("v") # strip "v" in target name
name = f"library-{name}@{lib_version}"
packages_new[name] = package # put the package under a new name
self.packages.update(packages_new)
pkg_versions[package] = version
# save platform packages for later
global libretuya_packages
libretuya_packages = self.packages
# enable packages required for framework libraries
for name, version in pkg_versions.items():
if name not in self.packages:
raise ValueError(f"Library '{name}' doesn't exist")
package = self.packages[name]
if "base_url" not in package:
if "#" not in package.get("version", ""):
click.secho(
f"Property 'base_url' is missing for '{name}'. "
"The version of this package can't be changed by the user.",
fg="red",
)
exit(1)
package["base_url"] = package["version"].partition("#")[0]
if package.get("version_prefix", False):
version = "v" + version
package["optional"] = False
package["version"] = package["base_url"] + "#" + version
# save custom options from env
self.custom_opts = {}
for key, value in options.items():
if not key.startswith("custom_"):
continue
self.custom_opts[key[7:]] = value
# store version numbers of all used packages
for package in self.get_installed_packages(with_optional=False):
package: PackageItem
version = package.metadata.version
version = str(version).partition("sha.")[0]
version = version.strip("+.")
version = version.rpartition("+")[2]
self.versions[package.metadata.name] = version
return super().configure_default_packages(options, targets)
@@ -246,10 +228,15 @@ class LibretuyaPlatform(PlatformBase):
if "_base" in board:
board._manifest = ltchiptool.Board.get_data(board._manifest)
# add "arduino" framework
has_arduino = any("arduino" in fw for fw in board.manifest["frameworks"])
if has_arduino:
family = board.get("build.family")
family = ltchiptool.Family.get(short_name=family)
# add "frameworks" key with the default "base"
board.manifest["frameworks"] = ["base"]
# add "arduino" framework if supported
if family.has_arduino_core:
board.manifest["frameworks"].append("arduino")
# add SDK package name
board.manifest["package"] = family.target_package
# inspired by platform-ststm32/platform.py
debug = board.manifest.get("debug", {})