* Ensure the virtual environment exists and dependencies are installed. * Returns true if all setup steps were already satisfied (fast path). * * @param {object} python - The result of findPython() * @param {boolean} forceRecreate - If true, delete and recreate the venv
(python, forceRecreate)
| 233 | * @param {boolean} forceRecreate - If true, delete and recreate the venv |
| 234 | */ |
| 235 | function ensureVenv(python, forceRecreate) { |
| 236 | mkdirSync(CONFIG_HOME, { recursive: true }); |
| 237 | |
| 238 | const marker = readMarker(); |
| 239 | const reqHash = requirementsHash(); |
| 240 | const pyExe = venvPython(); |
| 241 | |
| 242 | // Determine if the venv itself needs to be (re)created |
| 243 | let needsCreate = forceRecreate || !existsSync(pyExe); |
| 244 | |
| 245 | if (!needsCreate && marker) { |
| 246 | // Recreate if Python major.minor changed |
| 247 | const markerMinor = marker.python_version; |
| 248 | const currentMinor = `${python.version.major}.${python.version.minor}`; |
| 249 | if (markerMinor && markerMinor !== currentMinor) { |
| 250 | needsCreate = true; |
| 251 | } |
| 252 | |
| 253 | // Recreate if the recorded python path no longer exists |
| 254 | if (marker.python_path && !existsSync(marker.python_path)) { |
| 255 | needsCreate = true; |
| 256 | } |
| 257 | } |
| 258 | |
| 259 | let depsUpToDate = false; |
| 260 | if (!needsCreate && marker && marker.requirements_hash === reqHash) { |
| 261 | depsUpToDate = true; |
| 262 | } |
| 263 | |
| 264 | // Fast path: nothing to do |
| 265 | if (!needsCreate && depsUpToDate) { |
| 266 | return true; |
| 267 | } |
| 268 | |
| 269 | // --- Slow path: show setup progress --- |
| 270 | |
| 271 | log('[2/3] Setting up environment...'); |
| 272 | |
| 273 | if (needsCreate) { |
| 274 | if (existsSync(VENV_DIR)) { |
| 275 | log(' Removing old virtual environment...'); |
| 276 | rmSync(VENV_DIR, { recursive: true, force: true }); |
| 277 | } |
| 278 | |
| 279 | log(` Creating virtual environment at ~/.autoforge/venv/`); |
| 280 | const exeParts = python.exe.split(' '); |
| 281 | try { |
| 282 | execFileSync(exeParts[0], [...exeParts.slice(1), '-m', 'venv', VENV_DIR], { |
| 283 | encoding: 'utf8', |
| 284 | timeout: 120_000, |
| 285 | stdio: ['pipe', 'pipe', 'pipe'], |
| 286 | }); |
| 287 | } catch (err) { |
| 288 | die(`Failed to create virtual environment: ${err.message}`); |
| 289 | } |
| 290 | } |
| 291 | |
| 292 | // Install / update dependencies |
no test coverage detected