Skip to content

Commit dc34035

Browse files
author
PyCompiler ARK++
committed
feat: Implement YAML support for ARK configuration and synchronize BCASL plugin settings
1 parent ec0b2f9 commit dc34035

4 files changed

Lines changed: 303 additions & 43 deletions

File tree

Core/Compiler/ark_config_loader.py

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -105,10 +105,9 @@
105105
"include_modules": [], # Modules to explicitly include
106106
},
107107

108-
# Plugins (BCASL/ACASL)
108+
# Plugins (BCASL)
109109
"plugins": {
110110
"bcasl_enabled": True, # Enable pre-compilation plugins
111-
"acasl_enabled": True, # Enable post-compilation plugins
112111
"plugin_timeout": 0, # Plugin timeout in seconds (0 = unlimited)
113112
},
114113

@@ -397,11 +396,10 @@ def create_default_ark_config(workspace_dir: str) -> bool:
397396
# - "hidden_module"
398397
399398
# ───────────────────────────────────────────────────────────────
400-
# PLUGINS (BCASL/ACASL)
399+
# PLUGINS (BCASL)
401400
# ───────────────────────────────────────────────────────────────
402401
plugins:
403402
bcasl_enabled: true # Enable pre-compilation plugins
404-
acasl_enabled: true # Enable post-compilation plugins
405403
plugin_timeout: 0 # Plugin timeout in seconds (0 = unlimited)
406404
407405
# ───────────────────────────────────────────────────────────────

Tests/test_ark_config_loader.py

Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
# SPDX-License-Identifier: Apache-2.0
2+
# Tests for Core/Compiler/ark_config_loader.py behaviors
3+
4+
from __future__ import annotations
5+
6+
import os
7+
from pathlib import Path
8+
import importlib
9+
10+
import pytest
11+
12+
13+
@pytest.fixture
14+
def mod():
15+
return importlib.import_module("Core.Compiler.ark_config_loader")
16+
17+
18+
def test_load_defaults_when_no_file(tmp_path: Path, mod):
19+
cfg = mod.load_ark_config(str(tmp_path))
20+
# Basic structure keys
21+
for key in ("exclusion_patterns", "inclusion_patterns", "pyinstaller", "nuitka", "output", "dependencies", "plugins", "advanced"):
22+
assert key in cfg
23+
# Inclusion defaults
24+
assert isinstance(cfg["inclusion_patterns"], list)
25+
assert any(p.endswith("*.py") for p in cfg["inclusion_patterns"])
26+
27+
28+
def test_create_default_config_file_idempotent(tmp_path: Path, mod):
29+
# First call should create file
30+
created_first = mod.create_default_ark_config(str(tmp_path))
31+
assert created_first is True
32+
conf_path = tmp_path / "ARK_Main_Config.yml"
33+
assert conf_path.is_file()
34+
# Second call should not overwrite and return False
35+
created_second = mod.create_default_ark_config(str(tmp_path))
36+
assert created_second is False
37+
38+
39+
def test_merge_user_config_and_normalization(tmp_path: Path, mod):
40+
# Write a minimal user config overriding nested values and adding custom patterns
41+
user_cfg = """
42+
pyinstaller:
43+
onefile: false
44+
windowed: true
45+
exclusion_patterns:
46+
- "custom_ignore/**"
47+
- "**/*.pyo"
48+
main_file_names:
49+
- main.py
50+
- start.py
51+
"""
52+
(tmp_path / "ARK_Main_Config.yml").write_text(user_cfg, encoding="utf-8")
53+
54+
cfg = mod.load_ark_config(str(tmp_path))
55+
56+
# Nested overrides applied
57+
assert cfg["pyinstaller"]["onefile"] is False
58+
assert cfg["pyinstaller"]["windowed"] is True
59+
60+
# Exclusion patterns contain defaults plus user entries (deduped)
61+
patterns = set(cfg["exclusion_patterns"])
62+
assert "custom_ignore/**" in patterns
63+
# Default like "**/*.pyc" should still be present
64+
assert any(p.endswith("*.pyc") for p in patterns)
65+
66+
# Normalized main_file_names list
67+
assert set(cfg["main_file_names"]) >= {"main.py", "start.py"}
68+
69+
70+
@pytest.mark.parametrize(
71+
"compiler_key",
72+
["pyinstaller", "nuitka", "cx_freeze"],
73+
)
74+
def test_get_compiler_options_present(tmp_path: Path, mod, compiler_key: str):
75+
cfg = mod.load_ark_config(str(tmp_path))
76+
opts = mod.get_compiler_options(cfg, compiler_key)
77+
assert isinstance(opts, dict)
78+
79+
80+
def test_option_accessors(tmp_path: Path, mod):
81+
cfg = mod.load_ark_config(str(tmp_path))
82+
assert isinstance(mod.get_output_options(cfg), dict)
83+
assert isinstance(mod.get_dependency_options(cfg), dict)
84+
assert isinstance(mod.get_plugin_options(cfg), dict)
85+
assert isinstance(mod.get_advanced_options(cfg), dict)
86+
87+
88+
def test_should_exclude_file_logic(tmp_path: Path, mod):
89+
# Create workspace and files
90+
ws = tmp_path
91+
(ws / "venv" / "lib").mkdir(parents=True)
92+
inside_ok = ws / "src" / "app.py"
93+
inside_ok.parent.mkdir(parents=True)
94+
inside_ok.write_text("print('x')", encoding="utf-8")
95+
excluded_by_pattern = ws / "venv" / "lib" / "x.py"
96+
excluded_by_pattern.write_text("print('y')", encoding="utf-8")
97+
98+
patterns = mod.DEFAULT_EXCLUSION_PATTERNS
99+
100+
# File outside workspace must be excluded
101+
assert mod.should_exclude_file("/tmp/somewhere_else.py", str(ws), patterns) is True
102+
103+
# File matching exclusion pattern is excluded
104+
assert mod.should_exclude_file(str(excluded_by_pattern), str(ws), patterns) is True
105+
106+
# Regular file inside workspace not matching patterns is not excluded
107+
assert mod.should_exclude_file(str(inside_ok), str(ws), patterns) is False

Tests/test_bcasl_loader_sync.py

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
# SPDX-License-Identifier: Apache-2.0
2+
# Tests for BCASL <-> ARK config synchronization and YAML behavior
3+
4+
from __future__ import annotations
5+
6+
from pathlib import Path
7+
import importlib
8+
import yaml
9+
10+
11+
def write_yaml(path: Path, data: dict):
12+
path.write_text(yaml.safe_dump(data, sort_keys=False, allow_unicode=True), encoding="utf-8")
13+
14+
15+
def read_yaml(path: Path) -> dict:
16+
return yaml.safe_load(path.read_text(encoding="utf-8")) or {}
17+
18+
19+
def test_sync_ark_bcasl_enabled_creates_and_updates_yaml(tmp_path: Path):
20+
mod = importlib.import_module("bcasl.Loader")
21+
22+
ws = tmp_path
23+
ark_path = ws / "ARK_Main_Config.yml"
24+
assert not ark_path.exists()
25+
26+
# Toggle to False -> should create the YAML and set plugins.bcasl_enabled False
27+
mod._sync_ark_bcasl_enabled(ws, False)
28+
assert ark_path.is_file()
29+
cfg = read_yaml(ark_path)
30+
assert cfg.get("plugins", {}).get("bcasl_enabled") is False
31+
32+
# Toggle to True -> update YAML accordingly
33+
mod._sync_ark_bcasl_enabled(ws, True)
34+
cfg2 = read_yaml(ark_path)
35+
assert cfg2.get("plugins", {}).get("bcasl_enabled") is True
36+
37+
38+
def test_bcasl_loader_ignores_enabled_in_bcasl_yaml_and_uses_ark(tmp_path: Path):
39+
mod = importlib.import_module("bcasl.Loader")
40+
41+
ws = tmp_path
42+
ark_path = ws / "ARK_Main_Config.yml"
43+
bcasl_path = ws / "bcasl.yml"
44+
45+
# Prepare ARK with bcasl disabled
46+
write_yaml(ark_path, {"plugins": {"bcasl_enabled": False, "plugin_timeout": 0}})
47+
48+
# Prepare a legacy bcasl.yml that wrongly contains an 'enabled' field
49+
write_yaml(bcasl_path, {
50+
"options": {"enabled": True, "plugin_timeout_s": 0},
51+
"plugins": {},
52+
"plugin_order": []
53+
})
54+
55+
cfg = mod._load_workspace_config(ws)
56+
# In-memory config must reflect ARK: enabled False regardless of YAML content
57+
opts = cfg.get("options", {})
58+
assert isinstance(opts, dict)
59+
assert opts.get("enabled") is False
60+
61+
# Persisted YAML must not be modified on read; still contains 'enabled' (legacy)
62+
y = read_yaml(bcasl_path)
63+
assert "enabled" in (y.get("options") or {})
64+
65+
66+
def test_bcasl_default_generation_omits_enabled_but_runtime_injects_from_ark(tmp_path: Path):
67+
mod = importlib.import_module("bcasl.Loader")
68+
69+
ws = tmp_path
70+
ark_path = ws / "ARK_Main_Config.yml"
71+
72+
# ARK enables BCASL
73+
write_yaml(ark_path, {"plugins": {"bcasl_enabled": True, "plugin_timeout": 1}})
74+
75+
# No bcasl.yml present triggers default generation path
76+
cfg = mod._load_workspace_config(ws)
77+
78+
# A bcasl.yml file should have been created without 'enabled' in options
79+
bpath = ws / "bcasl.yml"
80+
assert bpath.is_file()
81+
persisted = read_yaml(bpath)
82+
assert "enabled" not in (persisted.get("options") or {})
83+
84+
# But the in-memory config should include enabled: True
85+
assert cfg.get("options", {}).get("enabled") is True

0 commit comments

Comments
 (0)