Skip to content

Commit e5afc88

Browse files
committed
feat: consolidation de l'API build_command(context) pour tous les moteurs
1 parent f272148 commit e5afc88

6 files changed

Lines changed: 66 additions & 319 deletions

File tree

Core/engine/base.py

Lines changed: 7 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -90,41 +90,22 @@ def preflight(self, gui, file: str) -> bool:
9090
"""Perform preflight checks and setup. Return True if OK, False to abort."""
9191
return True
9292

93-
def build_command(self, gui, file: str) -> list[str]:
94-
"""Return the full command list including the program at index 0."""
95-
raise NotImplementedError
96-
97-
def build_command_from_context(self, context: "BuildContext") -> list[str]:
93+
def build_command(self, context: "BuildContext") -> list[str]:
9894
"""
9995
Return the full command list for a normalized build context.
10096
101-
Engines can override this method to support the new BuildContext-based
102-
contract without depending on GUI state or source files such as
103-
`ark.yml`/lock files. The default implementation is intentionally not
104-
provided because legacy `build_command(gui, file)` implementations may
105-
require UI state and would otherwise silently produce incomplete builds.
97+
This is the primary entry point for command generation. Engines should
98+
use the provided `context` for project settings and `self._config_overrides`
99+
for engine-specific options.
106100
"""
107101
raise NotImplementedError
108102

109-
def program_and_args(self, gui, file: str) -> Optional[tuple[str, list[str]]]:
110-
"""
111-
Resolve the program (executable path) and its arguments for QProcess.
112-
Default implementation splits build_command into program and args.
113-
Return None to abort.
114-
"""
115-
cmd = self.build_command(gui, file)
116-
if not cmd:
117-
return None
118-
return cmd[0], cmd[1:]
119-
120-
def program_and_args_from_context(
121-
self, context: "BuildContext"
122-
) -> Optional[tuple[str, list[str]]]:
103+
def program_and_args(self, context: "BuildContext") -> Optional[tuple[str, list[str]]]:
123104
"""
124105
Resolve the program and arguments for a normalized build context.
125-
Default implementation splits `build_command_from_context`.
106+
Default implementation splits `build_command`.
126107
"""
127-
cmd = self.build_command_from_context(context)
108+
cmd = self.build_command(context)
128109
if not cmd:
129110
return None
130111
return cmd[0], cmd[1:]

Ui/Cli/discovery.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -255,7 +255,7 @@ def scaffold_engine(target_name: str, root_dir: str | None = None) -> dict[str,
255255
' required_core_version = "1.0.0"',
256256
' required_sdk_version = "1.0.0"',
257257
"",
258-
" def build_command_from_context(self, context: BuildContext) -> list[str]:",
258+
" def build_command(self, context: BuildContext) -> list[str]:",
259259
" return [sys.executable, context.entry_point]",
260260
]
261261
)

engines/cx_freeze/__init__.py

Lines changed: 16 additions & 97 deletions
Original file line numberDiff line numberDiff line change
@@ -66,13 +66,22 @@ def preflight(self, gui, file: str) -> bool:
6666
"""Preflight check - dependencies are handled automatically by required_tools."""
6767
return True
6868

69-
def build_command_from_context(self, context: BuildContext) -> list[str]:
69+
def build_command(self, context: BuildContext) -> list[str]:
7070
"""Build a cx_Freeze command line from a normalized build context."""
7171
cfg = getattr(self, "_config_overrides", {})
7272
if not isinstance(cfg, dict):
7373
cfg = {}
7474

75-
cmd = [sys.executable, "-m", "cx_Freeze"]
75+
# Resolve executable (prefer venv if available)
76+
python_exe = sys.executable
77+
if hasattr(self, "_gui") and self._gui:
78+
venv_manager = getattr(self._gui, "venv_manager", None)
79+
if venv_manager:
80+
venv_path = venv_manager.resolve_project_venv()
81+
if venv_path:
82+
python_exe = venv_manager.python_path(venv_path)
83+
84+
cmd = [python_exe, "-m", "cx_Freeze"]
7685

7786
windowed_enabled = bool(cfg.get("windowed", False))
7887
if hasattr(self, "_cx_windowed") and self._cx_windowed is not None:
@@ -112,107 +121,17 @@ def build_command_from_context(self, context: BuildContext) -> list[str]:
112121
if source and destination:
113122
cmd.extend(["--include-files", f"{source}={destination}"])
114123

115-
cmd.extend(["--script", context.entry_point])
116-
return cmd
117-
118-
def build_command(self, gui, file: str) -> list[str]:
119-
"""Build the CX_Freeze command line."""
120-
try:
121-
cfg = getattr(self, "_config_overrides", {})
122-
if not isinstance(cfg, dict):
123-
cfg = {}
124-
venv_manager = getattr(gui, "venv_manager", None)
125-
126-
# Resolve venv python
127-
if venv_manager:
128-
venv_path = venv_manager.resolve_project_venv()
129-
if venv_path:
130-
python_path = venv_manager.python_path(venv_path)
131-
else:
132-
python_path = sys.executable
133-
else:
134-
python_path = sys.executable
135-
136-
# Start with python -m cx_Freeze
137-
cmd = [python_path, "-m", "cx_Freeze"]
138-
139-
# Add options from UI
140-
# Windowed mode (Windows only)
141-
windowed = self._get_opt("windowed")
142-
windowed_enabled = bool(cfg.get("windowed", False))
143-
if windowed is not None:
144-
windowed_enabled = bool(windowed.isChecked())
145-
if windowed_enabled and platform.system() == "Windows":
146-
cmd.extend(["--base", "Win32GUI"])
147-
148-
# Output directory
149-
output_dir = self._get_input("output_dir")
150-
output_dir_value = str(cfg.get("output_dir") or "").strip()
151-
if output_dir and output_dir.text().strip():
152-
output_dir_value = output_dir.text().strip()
153-
if output_dir_value:
154-
cmd.extend(["--target-dir", output_dir_value])
155-
156-
# Icon
157-
selected_icon = ""
158-
if hasattr(self, "_selected_icon") and self._selected_icon:
159-
selected_icon = str(self._selected_icon).strip()
160-
if not selected_icon:
161-
selected_icon = str(cfg.get("selected_icon") or "").strip()
162-
if selected_icon:
163-
cmd.extend(["--icon", selected_icon])
164-
165-
# Target name
166-
target_name = self._get_input("target_name")
167-
target_name_value = str(cfg.get("target_name") or "").strip()
168-
if target_name and target_name.text().strip():
169-
target_name_value = target_name.text().strip()
170-
if target_name_value:
171-
cmd.extend(["--target-name", target_name_value])
172-
173-
# Debug / verbose
174-
debug = self._get_opt("debug")
175-
debug_enabled = bool(cfg.get("debug", False))
176-
if debug is not None:
177-
debug_enabled = bool(debug.isChecked())
178-
if debug_enabled:
179-
cmd.append("--debug")
180-
verbose = self._get_opt("verbose")
181-
verbose_enabled = bool(cfg.get("verbose", False))
182-
if verbose is not None:
183-
verbose_enabled = bool(verbose.isChecked())
184-
if verbose_enabled:
185-
cmd.append("--verbose")
186-
187-
# Auto-mapping args (mapping.json / auto builder)
124+
# Auto-mapping args (mapping.json / auto builder)
125+
if hasattr(self, "_gui") and self._gui:
188126
try:
189-
auto_args = compute_auto_for_engine(gui, self.id)
127+
auto_args = compute_auto_for_engine(self._gui, self.id)
190128
if auto_args:
191129
cmd.extend(auto_args)
192130
except Exception:
193131
pass
194132

195-
# Add the target script
196-
cmd.extend(["--script", file])
197-
198-
return cmd
199-
200-
except Exception as e:
201-
try:
202-
if hasattr(gui, "log"):
203-
log_with_level(
204-
gui, "error", f"Erreur construction commande CX_Freeze: {e}"
205-
)
206-
except Exception:
207-
pass
208-
return []
209-
210-
def program_and_args(self, gui, file: str) -> Optional[tuple[str, list[str]]]:
211-
"""Return the program and args for QProcess."""
212-
cmd = self.build_command(gui, file)
213-
if not cmd:
214-
return None
215-
return cmd[0], cmd[1:]
133+
cmd.extend(["--script", context.entry_point])
134+
return cmd
216135

217136
def environment(self) -> Optional[dict[str, str]]:
218137
"""Return environment variables for the compilation process."""

engines/nuitka/__init__.py

Lines changed: 21 additions & 93 deletions
Original file line numberDiff line numberDiff line change
@@ -72,28 +72,37 @@ def preflight(self, gui, file: str) -> bool:
7272
"""Preflight check - dependencies are handled automatically by required_tools."""
7373
return True
7474

75-
def build_command_from_context(self, context: BuildContext) -> list[str]:
75+
def build_command(self, context: BuildContext) -> list[str]:
7676
"""Build a Nuitka command line from a normalized build context."""
7777
cfg = getattr(self, "_config_overrides", {})
7878
if not isinstance(cfg, dict):
7979
cfg = {}
8080

81-
cmd = [sys.executable, "-m", "nuitka"]
81+
# Resolve executable (prefer venv if available)
82+
python_exe = sys.executable
83+
if hasattr(self, "_gui") and self._gui:
84+
venv_manager = getattr(self._gui, "venv_manager", None)
85+
if venv_manager:
86+
venv_path = venv_manager.resolve_project_venv()
87+
if venv_path:
88+
python_exe = venv_manager.python_path(venv_path)
89+
90+
cmd = [python_exe, "-m", "nuitka"]
8291

8392
standalone_enabled = bool(cfg.get("standalone", False))
84-
if hasattr(self, "_nuitka_standalone"):
93+
if hasattr(self, "_nuitka_standalone") and self._nuitka_standalone is not None:
8594
standalone_enabled = bool(self._nuitka_standalone.isChecked())
8695
if standalone_enabled:
8796
cmd.append("--standalone")
8897

8998
onefile_enabled = bool(cfg.get("onefile", False))
90-
if hasattr(self, "_nuitka_onefile"):
99+
if hasattr(self, "_nuitka_onefile") and self._nuitka_onefile is not None:
91100
onefile_enabled = bool(self._nuitka_onefile.isChecked())
92101
if onefile_enabled:
93102
cmd.append("--onefile")
94103

95104
disable_console = bool(cfg.get("disable_console", False))
96-
if hasattr(self, "_nuitka_disable_console"):
105+
if hasattr(self, "_nuitka_disable_console") and self._nuitka_disable_console is not None:
97106
disable_console = bool(self._nuitka_disable_console.isChecked())
98107
if disable_console:
99108
cmd.append("--windows-disable-console")
@@ -107,8 +116,8 @@ def build_command_from_context(self, context: BuildContext) -> list[str]:
107116
cmd.append(f"--output-filename={output_name}")
108117

109118
icon_path = str(context.icon or cfg.get("selected_icon") or "").strip()
110-
if not icon_path:
111-
icon_path = str(getattr(self, "_nuitka_selected_icon", "") or "").strip()
119+
if not icon_path and hasattr(self, "_nuitka_selected_icon") and self._nuitka_selected_icon:
120+
icon_path = str(self._nuitka_selected_icon).strip()
112121
if icon_path:
113122
cmd.append(f"--windows-icon-from-ico={icon_path}")
114123

@@ -129,98 +138,17 @@ def build_command_from_context(self, context: BuildContext) -> list[str]:
129138
if source and destination:
130139
cmd.append(f"--include-data-dir={source}={destination}")
131140

132-
cmd.append(context.entry_point)
133-
return cmd
134-
135-
def build_command(self, gui, file: str) -> list[str]:
136-
"""Build the Nuitka command line."""
137-
try:
138-
cfg = getattr(self, "_config_overrides", {})
139-
if not isinstance(cfg, dict):
140-
cfg = {}
141-
142-
venv_manager = getattr(gui, "venv_manager", None)
143-
144-
# Resolve venv python
145-
if venv_manager:
146-
venv_path = venv_manager.resolve_project_venv()
147-
if venv_path:
148-
python_path = venv_manager.python_path(venv_path)
149-
else:
150-
python_path = sys.executable
151-
else:
152-
python_path = sys.executable
153-
154-
# Start with python -m nuitka
155-
cmd = [python_path, "-m", "nuitka"]
156-
157-
# Standalone mode
158-
standalone_enabled = bool(cfg.get("standalone", False))
159-
if hasattr(self, "_nuitka_standalone"):
160-
standalone_enabled = bool(self._nuitka_standalone.isChecked())
161-
if standalone_enabled:
162-
cmd.append("--standalone")
163-
164-
# Onefile mode
165-
onefile_enabled = bool(cfg.get("onefile", False))
166-
if hasattr(self, "_nuitka_onefile"):
167-
onefile_enabled = bool(self._nuitka_onefile.isChecked())
168-
if onefile_enabled:
169-
cmd.append("--onefile")
170-
171-
# Windowed (no console)
172-
disable_console = bool(cfg.get("disable_console", False))
173-
if hasattr(self, "_nuitka_disable_console"):
174-
disable_console = bool(self._nuitka_disable_console.isChecked())
175-
if disable_console:
176-
cmd.append("--windows-disable-console")
177-
178-
# Output directory
179-
output_dir_value = str(cfg.get("output_dir") or "").strip()
180-
if (
181-
hasattr(self, "_nuitka_output_dir")
182-
and self._nuitka_output_dir.text().strip()
183-
):
184-
output_dir_value = self._nuitka_output_dir.text().strip()
185-
if output_dir_value:
186-
cmd.append(f"--output-dir={output_dir_value}")
187-
188-
# Icon
189-
selected_icon = getattr(self, "_nuitka_selected_icon", None)
190-
if not selected_icon:
191-
selected_icon = cfg.get("selected_icon")
192-
if selected_icon:
193-
cmd.extend(["--windows-icon", selected_icon])
194-
195-
# Auto-mapping args (mapping.json / auto builder)
141+
# Auto-mapping args (mapping.json / auto builder)
142+
if hasattr(self, "_gui") and self._gui:
196143
try:
197-
auto_args = compute_auto_for_engine(gui, self.id)
144+
auto_args = compute_auto_for_engine(self._gui, self.id)
198145
if auto_args:
199146
cmd.extend(auto_args)
200147
except Exception:
201148
pass
202149

203-
# Add the target file
204-
cmd.append(file)
205-
206-
return cmd
207-
208-
except Exception as e:
209-
try:
210-
if hasattr(gui, "log"):
211-
log_with_level(
212-
gui, "error", f"Erreur construction commande Nuitka: {e}"
213-
)
214-
except Exception:
215-
pass
216-
return []
217-
218-
def program_and_args(self, gui, file: str) -> Optional[tuple[str, list[str]]]:
219-
"""Return the program and args for QProcess."""
220-
cmd = self.build_command(gui, file)
221-
if not cmd:
222-
return None
223-
return cmd[0], cmd[1:]
150+
cmd.append(context.entry_point)
151+
return cmd
224152

225153
def environment(self) -> Optional[dict[str, str]]:
226154
"""Return environment variables for the compilation process."""

0 commit comments

Comments
 (0)