Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
89 changes: 89 additions & 0 deletions pycompiler_ark/Core/engine/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,83 @@
from __future__ import annotations

import time
from dataclasses import dataclass
from typing import TYPE_CHECKING, Callable, Optional

if TYPE_CHECKING:
from pycompiler_ark.Core.engine.build_context import BuildContext


@dataclass(frozen=True)
class EngineMeta:
"""Métadonnées d'un moteur de compilation."""

id: str
name: str
version: str
required_core_version: str = "1.0.0"
required_sdk_version: str = "1.0.0"
description: str = ""
author: str = ""

def __post_init__(self) -> None:
nid = str(self.id or "").strip()
nname = str(self.name or "").strip()
nversion = str(self.version or "").strip()
if not nid:
raise ValueError("EngineMeta invalide: 'id' requis")
if not nname:
raise ValueError("EngineMeta invalide: 'name' requis")
if not nversion:
raise ValueError("EngineMeta invalide: 'version' requis")
object.__setattr__(self, "id", nid)
object.__setattr__(self, "name", nname)
object.__setattr__(self, "version", nversion)
object.__setattr__(self, "required_core_version", str(self.required_core_version or "1.0.0").strip() or "1.0.0")
object.__setattr__(self, "required_sdk_version", str(self.required_sdk_version or "1.0.0").strip() or "1.0.0")
object.__setattr__(self, "description", str(self.description or "").strip())
object.__setattr__(self, "author", str(self.author or "").strip())


def resolve_engine_meta(engine_or_cls: object) -> EngineMeta:
"""Resolve engine metadata from a meta object or legacy class attributes."""

meta = getattr(engine_or_cls, "meta", None)
if isinstance(meta, EngineMeta):
return meta

if isinstance(meta, dict):
return EngineMeta(
id=str(meta.get("id") or getattr(engine_or_cls, "id", "") or "base"),
name=str(meta.get("name") or getattr(engine_or_cls, "name", "") or "BaseEngine"),
version=str(meta.get("version") or getattr(engine_or_cls, "version", "") or "1.0.0"),
required_core_version=str(
meta.get("required_core_version")
or getattr(engine_or_cls, "required_core_version", "1.0.0")
),
required_sdk_version=str(
meta.get("required_sdk_version")
or getattr(engine_or_cls, "required_sdk_version", "1.0.0")
),
description=str(meta.get("description") or ""),
author=str(meta.get("author") or ""),
)

return EngineMeta(
id=str(getattr(engine_or_cls, "id", "") or "base"),
name=str(getattr(engine_or_cls, "name", "") or "BaseEngine"),
version=str(getattr(engine_or_cls, "version", "") or "1.0.0"),
required_core_version=str(
getattr(engine_or_cls, "required_core_version", "1.0.0")
),
required_sdk_version=str(
getattr(engine_or_cls, "required_sdk_version", "1.0.0")
),
description=str(getattr(engine_or_cls, "description", "") or ""),
author=str(getattr(engine_or_cls, "author", "") or ""),
)


def log_i18n_level(gui, level: str, fr: str, en: str) -> None:
"""Minimal i18n log helper to avoid engine loader <-> engine_sdk circular imports."""
try:
Expand Down Expand Up @@ -81,12 +152,30 @@ class CompilerEngine:
provided via the `gui` object.
"""

meta: EngineMeta = EngineMeta(id="base", name="BaseEngine", version="1.0.0")
id: str = "base"
name: str = "BaseEngine"
version: str = "1.0.0"
required_core_version: str = "1.0.0"
required_sdk_version: str = "1.0.0"

def __init_subclass__(cls, **kwargs):
super().__init_subclass__(**kwargs)
try:
resolved = resolve_engine_meta(cls)
cls.meta = resolved
cls.id = resolved.id
cls.name = resolved.name
cls.version = resolved.version
cls.required_core_version = resolved.required_core_version
cls.required_sdk_version = resolved.required_sdk_version
if resolved.description and not getattr(cls, "description", None):
cls.description = resolved.description
if resolved.author and not getattr(cls, "author", None):
cls.author = resolved.author
except Exception:
pass

def preflight(self, gui, file: str) -> bool:
"""Perform preflight checks and setup. Return True if OK, False to abort."""
return True
Expand Down
40 changes: 22 additions & 18 deletions pycompiler_ark/Core/engine/validator.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@
from dataclasses import dataclass
from typing import List, Tuple

from pycompiler_ark.Core.engine.base import resolve_engine_meta


@dataclass
class EngineCompatibilityCheckResult:
Expand Down Expand Up @@ -90,13 +92,14 @@ def check_engine_compatibility(
Returns:
EngineCompatibilityCheckResult with compatibility information
"""
engine_id = getattr(engine_class, "id", "unknown")
engine_name = getattr(engine_class, "name", "Unknown Engine")
meta = resolve_engine_meta(engine_class)
engine_id = meta.id
engine_name = meta.name
missing_requirements = []

# Get required versions from engine class
required_core_version = getattr(engine_class, "required_core_version", "1.0.0")
required_sdk_version = getattr(engine_class, "required_sdk_version", "1.0.0")
# Get required versions from engine metadata
required_core_version = meta.required_core_version
required_sdk_version = meta.required_sdk_version

# Check Core compatibility: current >= required (accept equal or higher versions)
current_core = parse_version(core_version)
Expand Down Expand Up @@ -154,39 +157,39 @@ def validate_engines_compatibility(
try:
# In strict mode, reject engines that don't specify requirements
if strict_mode:
meta = resolve_engine_meta(engine)
has_explicit_requirements = (
getattr(engine, "required_core_version", "1.0.0") != "1.0.0"
or getattr(engine, "required_sdk_version", "1.0.0") != "1.0.0"
meta.required_core_version != "1.0.0"
or meta.required_sdk_version != "1.0.0"
)

if not has_explicit_requirements:
result = EngineCompatibilityCheckResult(
engine_id=getattr(engine, "id", "unknown"),
engine_name=getattr(engine, "name", "Unknown"),
engine_id=meta.id,
engine_name=meta.name,
is_compatible=False,
missing_requirements=[
"No explicit version requirements specified"
],
error_message=f"Engine '{getattr(engine, 'name', 'Unknown')}' ({getattr(engine, 'id', 'unknown')}) does not specify version requirements. "
f"Please add required_core_version and required_sdk_version class attributes.",
error_message=f"Engine '{meta.name}' ({meta.id}) does not specify version requirements. "
f"Please add an EngineMeta with required_core_version and required_sdk_version.",
)
incompatible_results.append(result)
continue

# Check compatibility
result = check_engine_compatibility(
engine, core_version, engine_sdk_version
)
result = check_engine_compatibility(engine, core_version, engine_sdk_version)

if result.is_compatible:
compatible_engines.append(engine)
else:
incompatible_results.append(result)

except Exception as e:
meta = resolve_engine_meta(engine)
result = EngineCompatibilityCheckResult(
engine_id=getattr(engine, "id", "unknown"),
engine_name=getattr(engine, "name", "Unknown"),
engine_id=meta.id,
engine_name=meta.name,
is_compatible=False,
missing_requirements=[],
error_message=f"Error validating engine: {str(e)}",
Expand All @@ -207,8 +210,9 @@ def print_engine_compatibility_report(

print(f"\n✓ Compatible: {len(compatible_engines)}")
for engine in compatible_engines:
engine_name = getattr(engine, "name", "Unknown")
engine_id = getattr(engine, "id", "unknown")
meta = resolve_engine_meta(engine)
engine_name = meta.name
engine_id = meta.id
print(f" - {engine_name} ({engine_id})")

print(f"\n✗ Incompatible: {len(incompatible_results)}")
Expand Down
3 changes: 2 additions & 1 deletion pycompiler_ark/engine_sdk/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
from pycompiler_ark.Core.engine.build_context import BuildContext

# Re-export the base interface used by the host
from .base import CompilerEngine
from .base import CompilerEngine, EngineMeta
from pycompiler_ark.Core.engine.registry import translate
from .utils import resolve_executable # executable resolution helper (SDK)
from .utils import open_path
Expand All @@ -31,6 +31,7 @@
__all__ = [
"engine_register",
"CompilerEngine",
"EngineMeta",
"resolve_executable",
"open_path",
"translate",
Expand Down
4 changes: 2 additions & 2 deletions pycompiler_ark/engine_sdk/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,6 @@
from __future__ import annotations

# Stable re-export of the host base class
from pycompiler_ark.Core.engine.base import CompilerEngine # type: ignore[F401]
from pycompiler_ark.Core.engine.base import EngineMeta, CompilerEngine # type: ignore[F401]

__all__ = ["CompilerEngine"]
__all__ = ["CompilerEngine", "EngineMeta"]
11 changes: 6 additions & 5 deletions pycompiler_ark/engines/cx_freeze/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
from pycompiler_ark.engine_sdk import (
BuildContext,
CompilerEngine,
EngineMeta,
engine_register,
translate,
)
Expand Down Expand Up @@ -58,11 +59,11 @@ class CXFreezeEngine(CompilerEngine):
- Icon specification
"""

id: str = "cx_freeze"
name: str = "CX_Freeze"
version: str = "1.1.0"
required_core_version: str = "1.0.0"
required_sdk_version: str = "1.0.0"
meta = EngineMeta(
id="cx_freeze",
name="CX_Freeze",
version="1.1.0",
)

@property
def required_tools(self) -> dict[str, list[str]]:
Expand Down
11 changes: 6 additions & 5 deletions pycompiler_ark/engines/nuitka/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
from pycompiler_ark.engine_sdk import (
BuildContext,
CompilerEngine,
EngineMeta,
engine_register,
translate,
)
Expand All @@ -55,11 +56,11 @@ class NuitkaEngine(CompilerEngine):
- Icon specification
"""

id: str = "nuitka"
name: str = "Nuitka"
version: str = "1.1.0"
required_core_version: str = "1.0.0"
required_sdk_version: str = "1.0.0"
meta = EngineMeta(
id="nuitka",
name="Nuitka",
version="1.1.0",
)

@property
def required_tools(self) -> dict[str, list[str]]:
Expand Down
11 changes: 6 additions & 5 deletions pycompiler_ark/engines/pyinstaller/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
from pycompiler_ark.engine_sdk import (
BuildContext,
CompilerEngine,
EngineMeta,
engine_register,
translate,
)
Expand Down Expand Up @@ -59,11 +60,11 @@ class PyInstallerEngine(CompilerEngine):
- Icon specification
"""

id: str = "pyinstaller"
name: str = "PyInstaller"
version: str = "1.1.0"
required_core_version: str = "1.0.0"
required_sdk_version: str = "1.0.0"
meta = EngineMeta(
id="pyinstaller",
name="PyInstaller",
version="1.1.0",
)

@property
def required_tools(self) -> dict[str, list[str]]:
Expand Down