# Environment check - use local nodejs/node and python/x64 only [Console]::OutputEncoding = [System.Text.Encoding]::UTF8 $OutputEncoding = [System.Text.Encoding]::UTF8 chcp 65001 | Out-Null $scriptRoot = $PSScriptRoot if (-not $scriptRoot) { $scriptRoot = Split-Path -Parent $MyInvocation.MyCommand.Path } if (-not $scriptRoot) { $scriptRoot = (Get-Location).Path } # 架构:根据 PROCESSOR_ARCHITECTURE $arch = if ($env:PROCESSOR_ARCHITECTURE -eq 'ARM64') { 'arm64' } else { 'x64' } # 从 config.js 读取路径(需先找到 node 来执行 get-node-paths.js) $nodeExeBootstrap = $null foreach ($tryNode in @( (Join-Path $scriptRoot ('nodejs\' + $arch + '\node\node.exe')), (Join-Path $scriptRoot 'nodejs\node\node.exe') )) { if (Test-Path $tryNode) { $nodeExeBootstrap = $tryNode; break } } $getPathsScript = Join-Path $scriptRoot 'configs\get-node-paths.js' if ($nodeExeBootstrap -and (Test-Path $getPathsScript)) { try { Push-Location $scriptRoot $cfgJson = & $nodeExeBootstrap $getPathsScript 2>$null if ($cfgJson) { $cfg = $cfgJson | ConvertFrom-Json $nodeDir = $cfg.nodeDir $npmCmd = $cfg.npmCmdPath $npmCliPath = $cfg.npmCliPath if ($cfg.pythonDir) { $pythonRoot = $cfg.pythonDir } if ($cfg.pythonVenvPath) { $venvPath = $cfg.pythonVenvPath } } } catch { } finally { Pop-Location } } if (-not $nodeDir) { $nodeDir = Join-Path $scriptRoot ('nodejs\' + $arch + '\node'); if (-not (Test-Path $nodeDir)) { $nodeDir = Join-Path $scriptRoot 'nodejs\node' } } if (-not $npmCliPath) { $npmCliPath = Join-Path $nodeDir 'node_modules\npm\bin\npm-cli.js' } if (-not $npmCmd) { $npmCmd = Join-Path $nodeDir 'npm.cmd' } $nodeExe = Join-Path $nodeDir 'node.exe' if (-not (Test-Path $nodeExe)) { $nodeExe = $null } if (-not (Test-Path $npmCmd)) { $npmCmd = $null } if (-not $pythonRoot) { $pythonRoot = Join-Path $scriptRoot ('python\' + $arch) } # Python 优先在 python/x64/py 下查找 $pythonExe = $null foreach ($p in @( (Join-Path $pythonRoot 'py\python.exe'), (Join-Path $pythonRoot 'env\Scripts\python.exe'), (Join-Path $pythonRoot 'python.exe') )) { if (Test-Path $p) { $pythonExe = $p; break } } Write-Host '' Write-Host ('Checking development environment (local nodejs/node and python/' + $arch + ')...') -ForegroundColor Cyan Write-Host '================================' -ForegroundColor Cyan Write-Host '' Write-Host 'Checking Node.js (local nodejs/node)...' -ForegroundColor Yellow if (-not $nodeExe) { Write-Host ('[X] Local Node not found. Put Node in: ' + $nodeDir) -ForegroundColor Red exit 1 } $nodeVersion = & $nodeExe --version 2>$null if ($nodeVersion) { Write-Host ('[OK] Node.js: ' + $nodeVersion) -ForegroundColor Green } else { Write-Host '[X] Local node.exe failed' -ForegroundColor Red exit 1 } Write-Host '' Write-Host 'Checking npm (local)...' -ForegroundColor Yellow # 使用已验证的 nodeDir 构建 npm 路径,确保检查正确 $npmCliPath = Join-Path $nodeDir 'node_modules\npm\bin\npm-cli.js' $npmCmd = Join-Path $nodeDir 'npm.cmd' if (-not (Test-Path $npmCmd)) { $npmCmd = $null } $nodeModulesPath = Join-Path $nodeDir 'node_modules' $npmBackupDir = Join-Path $scriptRoot ('nodejs\dependences\' + $arch + '\backup') $npmBackupNpmDir = Join-Path $npmBackupDir 'npm' New-Item -ItemType Directory -Force -Path $npmBackupDir | Out-Null $npmHealthy = $false if ((Test-Path $npmCliPath) -and $npmCmd) { $npmVersion = & $npmCmd --version 2>$null if ($npmVersion) { $npmHealthy = $true Write-Host ('[OK] npm: ' + $npmVersion + ' (already installed)') -ForegroundColor Green } } if (-not $npmHealthy) { Write-Host '[WARN] npm missing or broken, trying backup restore first...' -ForegroundColor Yellow if (Test-Path $npmBackupNpmDir) { New-Item -ItemType Directory -Force -Path $nodeModulesPath | Out-Null $nodeNpmDir = Join-Path $nodeModulesPath 'npm' if (Test-Path $nodeNpmDir) { Remove-Item -LiteralPath $nodeNpmDir -Recurse -Force } Copy-Item -LiteralPath $npmBackupNpmDir -Destination $nodeModulesPath -Recurse -Force if ((Test-Path $npmCliPath) -and $npmCmd) { $npmVersion = & $npmCmd --version 2>$null if ($npmVersion) { $npmHealthy = $true Write-Host ('[OK] npm restored from backup: ' + $npmVersion) -ForegroundColor Green } } } } if (-not $npmHealthy) { Write-Host '[WARN] Backup restore failed, installing/downloading npm...' -ForegroundColor Yellow $installNpmBat = Join-Path $nodeDir 'install-npm.bat' if (Test-Path $installNpmBat) { Write-Host 'Running install-npm.bat to install npm...' -ForegroundColor Yellow cmd /c "`"$installNpmBat`" /q" if ($LASTEXITCODE -ne 0) { Write-Host '[X] npm installation failed' -ForegroundColor Red exit 1 } if (-not (Test-Path $npmCliPath)) { Write-Host '[X] npm-cli.js still missing after install. Check network or run install-npm.bat manually.' -ForegroundColor Red exit 1 } $npmVersion = & $npmCmd --version 2>$null if (-not $npmVersion) { Write-Host '[X] npm installed but still unusable' -ForegroundColor Red exit 1 } $npmHealthy = $true Write-Host ('[OK] npm installed: ' + $npmVersion) -ForegroundColor Green $generateScript = Join-Path $scriptRoot 'nodejs\dependences\generate-nodejs-dependencies.js' if (Test-Path $generateScript) { Write-Host 'Running generate-nodejs-dependencies.js...' -ForegroundColor Yellow & $nodeExe $generateScript if ($LASTEXITCODE -ne 0) { Write-Host '[WARN] generate-nodejs-dependencies.js failed (will retry later)' -ForegroundColor Yellow } } } else { Write-Host ('[X] Run ' + $installNpmBat + ' to install npm') -ForegroundColor Red exit 1 } } if ($npmHealthy -and (Test-Path (Join-Path $nodeModulesPath 'npm'))) { if (Test-Path $npmBackupNpmDir) { Remove-Item -LiteralPath $npmBackupNpmDir -Recurse -Force } Copy-Item -LiteralPath (Join-Path $nodeModulesPath 'npm') -Destination $npmBackupDir -Recurse -Force Write-Host ('[OK] npm backup synced: ' + $npmBackupNpmDir) -ForegroundColor Green } # Use domestic npm registry for all subsequent npm operations if ($npmCmd) { Push-Location $scriptRoot & $npmCmd config set registry https://registry.npmmirror.com 2>$null Pop-Location } Write-Host '' Write-Host 'Checking Node.js dependencies (nodejs/node vs dependencies.txt)...' -ForegroundColor Yellow $nodeModulesPath = Join-Path $nodeDir 'node_modules' $depsTxt = Join-Path $scriptRoot ('nodejs\dependences\' + $arch + '\dependencies.txt') $nodeDependenciesScript = Join-Path $scriptRoot ('nodejs\dependences\' + $arch + '\nodejs-dependencies-install.js') # Ensure package.json deps (vite, react, etc.) are installed; updates dependencies.txt if (Test-Path $nodeDependenciesScript) { & $nodeExe $nodeDependenciesScript if ($LASTEXITCODE -ne 0) { Write-Host '[X] Node.js dependencies install failed' -ForegroundColor Red exit 1 } } # npm install prunes extraneous packages; npm (not in package.json) gets removed. Reinstall if missing. if (-not (Test-Path $npmCliPath)) { $installNpmBat = Join-Path $nodeDir 'install-npm.bat' if (Test-Path $installNpmBat) { Write-Host 'npm was pruned by npm install. Reinstalling npm...' -ForegroundColor Yellow cmd /c "`"$installNpmBat`" /q" if ($LASTEXITCODE -ne 0 -or -not (Test-Path $npmCliPath)) { Write-Host '[X] npm reinstall failed' -ForegroundColor Red exit 1 } Write-Host '[OK] npm restored' -ForegroundColor Green } } if (-not (Test-Path $nodeModulesPath)) { Write-Host '[X] nodejs/node/node_modules not found' -ForegroundColor Red exit 1 } if (-not (Test-Path $depsTxt)) { $generateScript = Join-Path $scriptRoot 'nodejs\dependences\generate-nodejs-dependencies.js' if (Test-Path $generateScript) { Write-Host 'dependencies.txt not found. Running generate-nodejs-dependencies.js...' -ForegroundColor Yellow & $nodeExe $generateScript if ($LASTEXITCODE -ne 0 -and -not (Test-Path $depsTxt)) { Write-Host 'Generate failed (node_modules may be empty). Running nodejs-dependencies-install...' -ForegroundColor Yellow if (Test-Path $nodeDependenciesScript) { & $nodeExe $nodeDependenciesScript if ($LASTEXITCODE -ne 0) { Write-Host '[X] Failed to install dependencies and create dependencies.txt' -ForegroundColor Red exit 1 } } if (-not (Test-Path $depsTxt)) { Write-Host '[X] dependencies.txt still not found: ' $depsTxt -ForegroundColor Red exit 1 } } } else { Write-Host '[X] dependencies.txt not found: ' $depsTxt -ForegroundColor Red exit 1 } } $requiredLines = Get-Content $depsTxt -Encoding UTF8 | Where-Object { $_.Trim() -and -not $_.Trim().StartsWith('#') } $missing = @() foreach ($line in $requiredLines) { $pkgSpec = $line.Trim().Split('==', 2)[0].Trim() if (-not $pkgSpec) { continue } if ($pkgSpec -match '^@([^/]+)/(.+)$') { $subPath = Join-Path $nodeModulesPath ('@' + $Matches[1]) $pkgPath = Join-Path $subPath $Matches[2] } else { $pkgPath = Join-Path $nodeModulesPath $pkgSpec } if (-not (Test-Path $pkgPath)) { $missing += $pkgSpec } } if ($missing.Count -gt 0) { Write-Host ('[X] Missing ' + $missing.Count + ' package(s) in nodejs/node/node_modules (per dependencies.txt):') -ForegroundColor Red $missing | Select-Object -First 15 | ForEach-Object { Write-Host ' - ' $_ -ForegroundColor Red } if ($missing.Count -gt 15) { Write-Host (' ... and ' + ($missing.Count - 15) + ' more') -ForegroundColor Red } if (Test-Path $nodeDependenciesScript) { Write-Host 'Running nodejs-dependencies-install.js to install missing...' -ForegroundColor Yellow & $nodeExe $nodeDependenciesScript if ($LASTEXITCODE -ne 0) { Write-Host '[X] Node dependencies installation failed' -ForegroundColor Red exit 1 } } else { exit 1 } } else { Write-Host ('[OK] Node dependencies match dependencies.txt (' + $requiredLines.Count + ' packages)') -ForegroundColor Green } $generateScript = Join-Path $scriptRoot 'nodejs\dependences\generate-nodejs-dependencies.js' if (Test-Path $generateScript) { & $nodeExe $generateScript 2>$null } Write-Host '' Write-Host ('Checking Python (local python/' + $arch + ')...') -ForegroundColor Yellow if (-not $pythonExe) { Write-Host ('[X] Local Python not found. Put Python in: ' + $pythonRoot) -ForegroundColor Red exit 1 } Write-Host '[OK] python found' -ForegroundColor Green Write-Host '' Write-Host 'Embedded Python (py): prefer backup restore, network only as last fallback...' -ForegroundColor Yellow $pyEmbeddedExe = Join-Path $pythonRoot 'py\python.exe' $embSitePackages = Join-Path $pythonRoot 'py\Lib\site-packages' $bakRoot = Join-Path $pythonRoot 'backup' $bakSitePackages = Join-Path $pythonRoot 'backup\site-packages' $pypiIndexUrl = 'https://pypi.tuna.tsinghua.edu.cn/simple' $pypiTrustedHost = 'pypi.tuna.tsinghua.edu.cn' New-Item -ItemType Directory -Force -Path $bakRoot | Out-Null New-Item -ItemType Directory -Force -Path $bakSitePackages | Out-Null if (Test-Path $pyEmbeddedExe) { $embeddedPipOk = $false $toolchainOk = $false & $pyEmbeddedExe -m pip --version 2>$null | Out-Null if ($LASTEXITCODE -eq 0) { $embeddedPipOk = $true } if (-not $embeddedPipOk) { Write-Host '[WARN] Embedded pip missing or broken; restoring from backup\site-packages (copy)...' -ForegroundColor Yellow Get-ChildItem -LiteralPath $bakSitePackages -ErrorAction SilentlyContinue | ForEach-Object { Copy-Item -LiteralPath $_.FullName -Destination $embSitePackages -Recurse -Force } & $pyEmbeddedExe -m pip --version 2>$null | Out-Null if ($LASTEXITCODE -eq 0) { $embeddedPipOk = $true Write-Host '[OK] pip restored from local backup (no download)' -ForegroundColor Green } } if ($embeddedPipOk) { & $pyEmbeddedExe -c "import pip,setuptools,wheel; import setuptools.build_meta" 2>$null | Out-Null if ($LASTEXITCODE -eq 0) { $toolchainOk = $true } } if (-not $toolchainOk) { Write-Host '[WARN] pip/setuptools/wheel incomplete; restore from backup\site-packages (copy)...' -ForegroundColor Yellow Get-ChildItem -LiteralPath $bakSitePackages -ErrorAction SilentlyContinue | ForEach-Object { Copy-Item -LiteralPath $_.FullName -Destination $embSitePackages -Recurse -Force } if ($embeddedPipOk) { & $pyEmbeddedExe -c "import pip,setuptools,wheel; import setuptools.build_meta" 2>$null | Out-Null if ($LASTEXITCODE -eq 0) { $toolchainOk = $true Write-Host '[OK] toolchain restored from backup copy' -ForegroundColor Green } } } if (-not $toolchainOk -and $embeddedPipOk) { Write-Host '[WARN] backup copy not enough; trying backup whl offline install...' -ForegroundColor Yellow & $pyEmbeddedExe -m pip install --no-index --find-links $bakRoot --upgrade pip setuptools wheel & $pyEmbeddedExe -c "import pip,setuptools,wheel; import setuptools.build_meta" 2>$null | Out-Null if ($LASTEXITCODE -eq 0) { $toolchainOk = $true Write-Host '[OK] toolchain repaired from backup wheels (offline)' -ForegroundColor Green } } if (-not $toolchainOk -and $embeddedPipOk) { Write-Host '[WARN] offline backup not enough; upgrading via Tsinghua mirror...' -ForegroundColor Yellow & $pyEmbeddedExe -m pip install -i $pypiIndexUrl --trusted-host $pypiTrustedHost --upgrade pip setuptools wheel & $pyEmbeddedExe -c "import pip,setuptools,wheel; import setuptools.build_meta" 2>$null | Out-Null if ($LASTEXITCODE -eq 0) { $toolchainOk = $true Write-Host '[OK] toolchain repaired via online upgrade' -ForegroundColor Green } } if ($toolchainOk) { foreach ($pkgDir in @('pip', 'setuptools', 'wheel', 'pkg_resources')) { $fromPkg = Join-Path $embSitePackages $pkgDir if (Test-Path $fromPkg) { Copy-Item -LiteralPath $fromPkg -Destination (Join-Path $bakSitePackages $pkgDir) -Recurse -Force } } Get-ChildItem -LiteralPath $embSitePackages -Directory -ErrorAction SilentlyContinue | Where-Object { $_.Name -match '^(pip|setuptools|wheel)-.+\.dist-info$' } | ForEach-Object { Copy-Item -LiteralPath $_.FullName -Destination (Join-Path $bakSitePackages $_.Name) -Recurse -Force } & $pyEmbeddedExe -m pip download pip setuptools wheel -d $bakRoot -i $pypiIndexUrl --trusted-host $pypiTrustedHost 2>$null Write-Host '[OK] Synced py\Lib\site-packages → backup\site-packages' -ForegroundColor Green } else { Write-Host '[WARN] Embedded Python toolchain still broken. Use python\x64\get-pip.py or repair manually.' -ForegroundColor Yellow } } Write-Host '' Write-Host 'Running python-enviroment-install.py (creates venv if missing, installs dependencies)...' -ForegroundColor Yellow if (-not $venvPath) { $venvPath = Join-Path $scriptRoot ('python\' + $arch + '\env') } $pythonDependenciesScript = Join-Path $scriptRoot ('python\' + $arch + '\python-enviroment-install.py') if (Test-Path $pythonDependenciesScript) { $env:PYTHON_VENV_PATH = $venvPath # 始终用本地 Python (py/python.exe) 运行,避免 venv 内脚本指向系统 Python (如 C:\programs\python) & $pythonExe $pythonDependenciesScript if ($LASTEXITCODE -ne 0) { Write-Host '[X] Python dependencies check/installation failed' -ForegroundColor Red exit 1 } } else { Write-Host ('[X] Not found: ' + $pythonDependenciesScript) -ForegroundColor Red Write-Host '[WARN] Continuing without Python dependency check...' -ForegroundColor Yellow } Write-Host '' # Final verification: npm must exist for run_react to start Vite if (-not (Test-Path $npmCliPath)) { Write-Host '[X] npm-cli.js not found. Run: nodejs\node\install-npm.bat' -ForegroundColor Red exit 1 } Write-Host '================================' -ForegroundColor Cyan Write-Host 'Environment check completed!' -ForegroundColor Green Write-Host 'All dependencies are ready. You can now start the project.' -ForegroundColor Green