diff --git a/idf_build_apps/__init__.py b/idf_build_apps/__init__.py index 24f8012..83ca93e 100644 --- a/idf_build_apps/__init__.py +++ b/idf_build_apps/__init__.py @@ -16,6 +16,7 @@ from .app import ( App, + AppDeserializer, CMakeApp, MakeApp, ) @@ -29,6 +30,7 @@ __all__ = [ 'App', + 'AppDeserializer', 'CMakeApp', 'MakeApp', 'find_apps', diff --git a/idf_build_apps/app.py b/idf_build_apps/app.py index 26b7636..34834f2 100644 --- a/idf_build_apps/app.py +++ b/idf_build_apps/app.py @@ -27,6 +27,7 @@ Version, ) from pydantic import ( + Field, computed_field, ) @@ -55,6 +56,7 @@ from .utils import ( BaseModel, BuildError, + Literal, files_matches_patterns, find_first_match, rmdir, @@ -84,8 +86,6 @@ class App(BaseModel): INDEX_PLACEHOLDER: t.ClassVar[str] = '@i' # replace it with the build index IDF_VERSION_PLACEHOLDER: t.ClassVar[str] = '@v' # replace it with the IDF version - BUILD_SYSTEM: t.ClassVar[str] = 'unknown' - SDKCONFIG_LINE_REGEX: t.ClassVar[t.Pattern] = re.compile(r"^([^=]+)=\"?([^\"\n]*)\"?\n*$") # could be assigned later, used for filtering out apps by supported_targets @@ -105,6 +105,7 @@ class App(BaseModel): sdkconfig_path: t.Optional[str] = None config_name: t.Optional[str] = None + build_system: Literal['unknown'] = 'unknown' build_status: BuildStatus = BuildStatus.UNKNOWN build_comment: t.Optional[str] = None @@ -179,7 +180,7 @@ def __init__( def __str__(self): return '({}) App {}, target {}, sdkconfig {}, build in {}, {} in {}s'.format( - self.BUILD_SYSTEM, + self.build_system, self.app_dir, self.target, self.sdkconfig_path or '(default)', @@ -679,10 +680,10 @@ def check_should_build( class MakeApp(App): - BUILD_SYSTEM = 'make' - MAKE_PROJECT_LINE: t.ClassVar[str] = r'include $(IDF_PATH)/make/project.mk' + build_system: Literal['make'] = 'make' + @property def supported_targets(self) -> t.List[str]: if self.MANIFEST: @@ -744,8 +745,6 @@ def is_app(cls, path: str) -> bool: class CMakeApp(App): - BUILD_SYSTEM = 'cmake' - # If these keys are present in sdkconfig.defaults, they will be extracted and passed to CMake SDKCONFIG_TEST_OPTS: t.ClassVar[t.List[str]] = [ 'EXCLUDE_COMPONENTS', @@ -761,6 +760,7 @@ class CMakeApp(App): CMAKE_PROJECT_LINE: t.ClassVar[str] = r'include($ENV{IDF_PATH}/tools/cmake/project.cmake)' cmake_vars: t.Dict[str, str] = {} + build_system: Literal['cmake'] = 'cmake' def _build( self, @@ -867,3 +867,12 @@ def is_app(cls, path: str) -> bool: return False return True + + +class AppDeserializer(BaseModel): + app: t.Union[App, CMakeApp, MakeApp] = Field(discriminator='build_system') + + @classmethod + def from_json(cls, json_data: t.Union[str, bytes, bytearray]) -> App: + json_dict = json.loads(json_data.strip()) + return cls.model_validate({'app': json_dict}).app diff --git a/idf_build_apps/utils.py b/idf_build_apps/utils.py index 35404a3..4d8b22c 100644 --- a/idf_build_apps/utils.py +++ b/idf_build_apps/utils.py @@ -24,6 +24,15 @@ LOGGER, ) +try: + from typing import ( + Literal, + ) +except ImportError: + from typing_extensions import ( # isort: skip # noqa: F401 + Literal, + ) + class ConfigRule: def __init__(self, file_name: str, config_name: t.Optional[str]) -> None: diff --git a/pyproject.toml b/pyproject.toml index b8f026e..b8614c8 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -127,3 +127,6 @@ select = [ ] line-length = 120 target-version = "py37" +typing-modules = [ + "idf_build_apps.utils" +] diff --git a/tests/test_app.py b/tests/test_app.py index 2286031..df3f0ff 100644 --- a/tests/test_app.py +++ b/tests/test_app.py @@ -2,7 +2,9 @@ # SPDX-License-Identifier: Apache-2.0 from idf_build_apps import ( + AppDeserializer, CMakeApp, + MakeApp, ) @@ -12,3 +14,21 @@ def test_serialization(): b = CMakeApp.model_validate_json(a_s) assert a == b + + +def test_deserialization(tmp_path): + a = CMakeApp('foo', 'bar') + b = MakeApp('foo', 'bar') + + assert a != b + + with open(tmp_path / 'test.txt', 'w') as fw: + fw.write(a.to_json() + '\n') + fw.write(b.to_json() + '\n') + + with open(tmp_path / 'test.txt') as fr: + a_s = AppDeserializer.from_json(fr.readline()) + b_s = AppDeserializer.from_json(fr.readline()) + + assert a == a_s + assert b == b_s