update instalelr
This commit is contained in:
@@ -53,27 +53,32 @@ Use `.config` from inside the CLI instead:
|
||||
|
||||
This keeps configuration inside the same table-and-selection model as the rest of the app.
|
||||
|
||||
## Installation From A Git Checkout
|
||||
## Installation
|
||||
|
||||
Requirements:
|
||||
|
||||
- Python 3.9 through 3.13
|
||||
- Git
|
||||
- Git (the bootstrap uses it to download the project)
|
||||
- PowerShell on Windows
|
||||
- `mpv` recommended for playback workflows
|
||||
|
||||
From the repository root, run:
|
||||
On Windows, run the bootstrap directly from PowerShell. It downloads the project
|
||||
and starts the installation for you:
|
||||
|
||||
```powershell
|
||||
Set-Location C:\path\to\Medios-Macina
|
||||
|
||||
Set-ExecutionPolicy -Scope Process -ExecutionPolicy Bypass
|
||||
.\scripts\bootstrap.ps1 -Editable
|
||||
|
||||
.\.venv\Scripts\Activate.ps1
|
||||
mm
|
||||
irm "https://code.glowers.club/goyimnose/Medios-Macina/raw/branch/main/scripts/bootstrap.ps1" | iex
|
||||
```
|
||||
|
||||
For an existing checkout, run this from the repository root:
|
||||
|
||||
```powershell
|
||||
.\scripts\bootstrap.ps1 -Editable
|
||||
```
|
||||
|
||||
Use `-NoMpv`, `-NoDeno`, or `-NoPlaywright` to skip optional external runtime
|
||||
installation when those components are already managed separately.
|
||||
|
||||
Notes:
|
||||
|
||||
- The bootstrap script creates `.venv`, installs the project, and exposes the `mm` and `medeia` console commands.
|
||||
|
||||
+63
-551
@@ -1,30 +1,29 @@
|
||||
<#
|
||||
<#!
|
||||
.SYNOPSIS
|
||||
Bootstrap a Python virtualenv and install the project on Windows (PowerShell).
|
||||
Bootstrap Medios-Macina on Windows.
|
||||
|
||||
.DESCRIPTION
|
||||
Creates a Python virtual environment (default: .venv), upgrades pip, installs the project
|
||||
(either editable or normal), and optionally creates Desktop and Start Menu shortcuts.
|
||||
When run from a checkout, this wrapper delegates to scripts/bootstrap.py. When
|
||||
the script is piped from the web, it downloads the canonical Python bootstrap
|
||||
to a temporary file so a checkout is not required first.
|
||||
|
||||
.EXAMPLE
|
||||
# Create .venv and install in editable mode, create Desktop shortcut
|
||||
.\scripts\bootstrap.ps1 -Editable -CreateDesktopShortcut
|
||||
irm "https://code.glowers.club/goyimnose/Medios-Macina/raw/branch/main/scripts/bootstrap.ps1" | iex
|
||||
|
||||
.EXAMPLE
|
||||
# Use a specific python executable and force overwrite existing venv
|
||||
.\scripts\bootstrap.ps1 -Python "C:\\Python39\\python.exe" -Force
|
||||
# Note: you may need to run PowerShell with ExecutionPolicy Bypass:
|
||||
# powershell -ExecutionPolicy Bypass -File .\scripts\bootstrap.ps1 -Editable
|
||||
.\scripts\bootstrap.ps1 -Editable -NoPlaywright
|
||||
#>
|
||||
|
||||
param(
|
||||
[switch]$Editable,
|
||||
[switch]$CreateDesktopShortcut,
|
||||
[switch]$CreateStartMenuShortcut,
|
||||
[string]$VenvPath = ".venv",
|
||||
[string]$VenvPath = "",
|
||||
[string]$Python = "",
|
||||
[switch]$Force,
|
||||
[switch]$NoInstall,
|
||||
[switch]$NoMpv,
|
||||
[switch]$NoDeno,
|
||||
[switch]$NoPlaywright,
|
||||
[string]$PlaywrightBrowsers = "chromium",
|
||||
[switch]$FixUrllib3,
|
||||
@@ -32,556 +31,69 @@ param(
|
||||
[switch]$Quiet
|
||||
)
|
||||
|
||||
# Resolve OS detection in a broad-compatible way
|
||||
try { $IsWindowsPlatform = [System.Runtime.InteropServices.RuntimeInformation]::IsOSPlatform([System.Runtime.InteropServices.OSPlatform]::Windows) } catch { $IsWindowsPlatform = $env:OS -match 'Windows' }
|
||||
$ErrorActionPreference = "Stop"
|
||||
$bootstrapUrl = "https://code.glowers.club/goyimnose/Medios-Macina/raw/branch/main/scripts/bootstrap.py"
|
||||
$scriptPath = $MyInvocation.MyCommand.Path
|
||||
$repoRoot = $null
|
||||
$bootstrapPath = $null
|
||||
$temporaryBootstrap = $false
|
||||
|
||||
function Write-Log {
|
||||
param([string]$msg,[string]$lvl="INFO")
|
||||
if (-not $Quiet) {
|
||||
if ($lvl -eq "ERROR") { Write-Host "[$lvl] $msg" -ForegroundColor Red } else { Write-Host "[$lvl] $msg" }
|
||||
if ($scriptPath) {
|
||||
$scriptDir = Split-Path -Parent $scriptPath
|
||||
$candidateRoot = (Resolve-Path (Join-Path $scriptDir "..")).Path
|
||||
if ((Test-Path (Join-Path $candidateRoot "CLI.py")) -and (Test-Path (Join-Path $candidateRoot "scripts\bootstrap.py"))) {
|
||||
$repoRoot = $candidateRoot
|
||||
$bootstrapPath = Join-Path $repoRoot "scripts\bootstrap.py"
|
||||
}
|
||||
}
|
||||
|
||||
function Ensure-Mpv {
|
||||
# mpv is used by some pipelines; try to ensure it's available on PATH.
|
||||
try {
|
||||
$mpvCmd = Get-Command mpv -ErrorAction SilentlyContinue
|
||||
if ($mpvCmd) {
|
||||
try {
|
||||
$v = & mpv --version 2>$null | Select-Object -First 1
|
||||
if ($v) { Write-Log "mpv found: $v" "INFO" } else { Write-Log "mpv found: $($mpvCmd.Path)" "INFO" }
|
||||
} catch {
|
||||
Write-Log "mpv found: $($mpvCmd.Path)" "INFO"
|
||||
}
|
||||
return
|
||||
}
|
||||
} catch {}
|
||||
|
||||
Write-Log "mpv not found on PATH; attempting to install..." "INFO"
|
||||
|
||||
try {
|
||||
if (Get-Command choco -ErrorAction SilentlyContinue) {
|
||||
& choco install mpv -y --no-progress | Out-Null
|
||||
} elseif (Get-Command scoop -ErrorAction SilentlyContinue) {
|
||||
& scoop install mpv | Out-Null
|
||||
} elseif (Get-Command winget -ErrorAction SilentlyContinue) {
|
||||
# Best-effort: winget may require a specific id depending on environment.
|
||||
& winget install --silent --accept-package-agreements --accept-source-agreements mpv | Out-Null
|
||||
} else {
|
||||
Write-Log "mpv not found and no supported package manager found (choco/scoop/winget). Install mpv and ensure it's on PATH." "ERROR"
|
||||
return
|
||||
}
|
||||
} catch {
|
||||
Write-Log "mpv install attempt failed: $_" "ERROR"
|
||||
return
|
||||
}
|
||||
|
||||
try {
|
||||
$mpvCmd2 = Get-Command mpv -ErrorAction SilentlyContinue
|
||||
if ($mpvCmd2) {
|
||||
try {
|
||||
$v2 = & mpv --version 2> $null | Select-Object -First 1
|
||||
if ($v2) { Write-Log "mpv installed: $v2" "INFO" } else { Write-Log "mpv installed: $($mpvCmd2.Path)" "INFO" }
|
||||
} catch {
|
||||
Write-Log "mpv installed: $($mpvCmd2.Path)" "INFO"
|
||||
}
|
||||
} else {
|
||||
Write-Log "mpv install attempted but mpv is still not on PATH. Install mpv manually." "ERROR"
|
||||
}
|
||||
} catch {}
|
||||
if (-not $bootstrapPath) {
|
||||
$bootstrapPath = Join-Path ([IO.Path]::GetTempPath()) ("medios-macina-bootstrap-{0}.py" -f ([guid]::NewGuid()))
|
||||
Invoke-WebRequest -Uri $bootstrapUrl -OutFile $bootstrapPath -UseBasicParsing
|
||||
$temporaryBootstrap = $true
|
||||
}
|
||||
|
||||
if ($IsWindowsPlatform) {
|
||||
Ensure-Mpv
|
||||
$pythonArgs = @()
|
||||
if ($Editable) { $pythonArgs += "--install-editable" }
|
||||
if ($NoInstall) { $pythonArgs += "--skip-deps" }
|
||||
if ($NoMpv) { $pythonArgs += "--no-mpv" }
|
||||
if ($NoDeno) { $pythonArgs += "--no-deno" }
|
||||
if ($NoPlaywright) { $pythonArgs += "--no-playwright" }
|
||||
if ($PlaywrightBrowsers) { $pythonArgs += @("--browsers", $PlaywrightBrowsers) }
|
||||
if ($Quiet) { $pythonArgs += "--quiet" }
|
||||
if ($Force) { $pythonArgs += "--yes" }
|
||||
|
||||
if ($VenvPath) {
|
||||
Write-Warning "-VenvPath is handled by the Python bootstrap's repository-local .venv setting."
|
||||
}
|
||||
if ($CreateDesktopShortcut -or $CreateStartMenuShortcut -or $FixUrllib3 -or $RemovePth) {
|
||||
Write-Warning "One or more legacy PowerShell-only options were ignored by the canonical Python bootstrap."
|
||||
}
|
||||
|
||||
# Track whether the user chose an interactive auto-fix (so we can auto-remove .pth files)
|
||||
$AutoFixInteractive = $false
|
||||
|
||||
function Find-Python {
|
||||
param([string]$preferred)
|
||||
$candidates = @()
|
||||
if ($preferred -and $preferred.Trim()) { $candidates += $preferred }
|
||||
$candidates += @("python","python3","py")
|
||||
foreach ($c in $candidates) {
|
||||
try {
|
||||
if ($c -eq "py") {
|
||||
$out = & py -3 -c "import sys, json; print(sys.executable)" 2>$null
|
||||
if ($out) { return $out.Trim() }
|
||||
} else {
|
||||
$out = & $c -c "import sys, json; print(sys.executable)" 2>$null
|
||||
if ($out) { return $out.Trim() }
|
||||
}
|
||||
} catch {}
|
||||
}
|
||||
return $null
|
||||
}
|
||||
|
||||
# operate from repo root (parent of scripts dir)
|
||||
$scriptDir = Split-Path -Parent $MyInvocation.MyCommand.Path
|
||||
$repoRoot = (Resolve-Path (Join-Path $scriptDir "..")).Path
|
||||
Set-Location $repoRoot
|
||||
$scriptsDir = Join-Path $repoRoot 'scripts'
|
||||
|
||||
$pythonExe = Find-Python -preferred $Python
|
||||
if (-not $pythonExe) { Write-Log "No Python interpreter found. Specify -Python <path> or install Python." "ERROR"; exit 2 }
|
||||
Write-Log "Using Python: $pythonExe"
|
||||
|
||||
# Full venv path
|
||||
try { $venvFull = (Resolve-Path -LiteralPath $VenvPath -ErrorAction SilentlyContinue).Path } catch { $venvFull = $null }
|
||||
if (-not $venvFull) { $venvFull = (Join-Path $repoRoot $VenvPath) }
|
||||
|
||||
# Handle existing venv
|
||||
$venvExists = Test-Path $venvFull
|
||||
if ($venvExists) {
|
||||
if ($Force) {
|
||||
Write-Log "Removing existing venv at $venvFull"
|
||||
Remove-Item -Recurse -Force $venvFull
|
||||
$venvExists = $false
|
||||
} else {
|
||||
# Quick health check: does the existing venv have a python executable?
|
||||
$venvPy1 = Join-Path $venvFull "Scripts\python.exe"
|
||||
$venvPy2 = Join-Path $venvFull "bin/python"
|
||||
$venvHasPython = $false
|
||||
try {
|
||||
if (Test-Path $venvPy1 -PathType Leaf -ErrorAction SilentlyContinue) { $venvHasPython = $true }
|
||||
elseif (Test-Path $venvPy2 -PathType Leaf -ErrorAction SilentlyContinue) { $venvHasPython = $true }
|
||||
} catch {}
|
||||
|
||||
if (-not $venvHasPython) {
|
||||
if ($Quiet) {
|
||||
Write-Log "Existing venv appears incomplete or broken and quiet mode prevents prompting. Use -Force to recreate." "ERROR"
|
||||
exit 4
|
||||
}
|
||||
$ans = Read-Host "$venvFull exists but appears invalid (no python executable). Overwrite to recreate? (y/N)"
|
||||
if ($ans -eq 'y' -or $ans -eq 'Y') {
|
||||
Write-Log "Removing broken venv at $venvFull"
|
||||
Remove-Item -Recurse -Force $venvFull
|
||||
$venvExists = $false
|
||||
} else {
|
||||
Write-Log "Aborted due to broken venv." "ERROR"; exit 4
|
||||
}
|
||||
} else {
|
||||
if ($Quiet) {
|
||||
Write-Log "Using existing venv at $venvFull (quiet mode)" "INFO"
|
||||
} else {
|
||||
$ans = Read-Host "$venvFull already exists. Overwrite? (y/N) (default: use existing venv)"
|
||||
if ($ans -eq 'y' -or $ans -eq 'Y') {
|
||||
Write-Log "Removing existing venv at $venvFull"
|
||||
Remove-Item -Recurse -Force $venvFull
|
||||
$venvExists = $false
|
||||
} else {
|
||||
Write-Log "Continuing using existing venv at $venvFull" "INFO"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (-not (Test-Path $venvFull)) {
|
||||
Write-Log "Creating venv at $venvFull"
|
||||
try {
|
||||
& $pythonExe -m venv $venvFull
|
||||
} catch {
|
||||
Write-Log "Failed to create venv: $_" "ERROR"; exit 3
|
||||
}
|
||||
} else {
|
||||
Write-Log "Using existing venv at $venvFull" "INFO"
|
||||
}
|
||||
|
||||
# Determine venv python executable
|
||||
$venvPython = Join-Path $venvFull "Scripts\python.exe"
|
||||
if (-not (Test-Path $venvPython)) { $venvPython = Join-Path $venvFull "bin/python" }
|
||||
if (-not (Test-Path $venvPython)) { Write-Log "Created venv but could not find python inside it." "ERROR"; exit 4 }
|
||||
|
||||
Write-Log "Using venv python: $venvPython"
|
||||
|
||||
if (-not $NoInstall) {
|
||||
# Suggest editable install for development checkouts (interactive git clones)
|
||||
if (-not $Editable) {
|
||||
$isGit = $false
|
||||
try {
|
||||
if (Test-Path (Join-Path $repoRoot '.git')) { $isGit = $true }
|
||||
elseif ((Get-Command git -ErrorAction SilentlyContinue) -ne $null) {
|
||||
try { $gitOut = & git -C $repoRoot rev-parse --is-inside-work-tree 2>$null; if ($gitOut -eq 'true') { $isGit = $true } } catch {}
|
||||
}
|
||||
} catch {}
|
||||
if ($isGit) {
|
||||
$Editable = $true
|
||||
Write-Log "Detected development checkout; installing in editable mode for development." "INFO"
|
||||
}
|
||||
}
|
||||
|
||||
Write-Log "Upgrading pip, setuptools, wheel"
|
||||
try { & $venvPython -m pip install -U pip setuptools wheel } catch { Write-Log "pip upgrade failed: $_" "ERROR"; exit 5 }
|
||||
|
||||
if ($Editable) { $editable_label = "(editable)" } else { $editable_label = "" }
|
||||
Write-Log ("Installing project {0}" -f $editable_label)
|
||||
try {
|
||||
if ($Editable) { & $venvPython -m pip install -e $scriptsDir } else { & $venvPython -m pip install $scriptsDir }
|
||||
} catch {
|
||||
Write-Log "pip install failed: $_" "ERROR"; exit 6
|
||||
}
|
||||
|
||||
# Verify top-level 'CLI' import and (if missing) attempt to make it available
|
||||
Write-Log "Verifying installed CLI import..."
|
||||
try {
|
||||
& $venvPython -c "import importlib; importlib.import_module('scripts.cli_entry')" 2>$null
|
||||
if ($LASTEXITCODE -eq 0) { Write-Log "OK: 'scripts.cli_entry' is importable in the venv." }
|
||||
} catch {}
|
||||
|
||||
try {
|
||||
& $venvPython -c "import importlib; importlib.import_module('CLI')" 2>$null
|
||||
if ($LASTEXITCODE -eq 0) { Write-Log "Top-level 'CLI' is importable in the venv." }
|
||||
else {
|
||||
Write-Log "Top-level 'CLI' not importable; writing venv site-packages .pth pointing at repo root..." "INFO"
|
||||
|
||||
$siteDir = (& $venvPython -c "import sysconfig; print(sysconfig.get_paths().get('purelib',''))" 2>$null).Trim()
|
||||
if (-not $siteDir -or -not (Test-Path $siteDir)) {
|
||||
Write-Log "ERROR: unable to determine venv site-packages directory (purelib='$siteDir'); aborting." "ERROR"
|
||||
exit 6
|
||||
}
|
||||
|
||||
$pth = Join-Path $siteDir 'medeia_repo.pth'
|
||||
Set-Content -LiteralPath $pth -Value $repoRoot -Encoding UTF8
|
||||
Write-Log "Wrote .pth adding repo root to venv site-packages: $pth" "INFO"
|
||||
|
||||
& $venvPython -c "import importlib; importlib.import_module('CLI')" 2>$null
|
||||
if ($LASTEXITCODE -eq 0) {
|
||||
Write-Log "OK: top-level 'CLI' is now importable (after .pth)." "INFO"
|
||||
} else {
|
||||
Write-Log "ERROR: top-level 'CLI' still not importable after writing .pth ($pth); aborting." "ERROR"
|
||||
exit 6
|
||||
}
|
||||
}
|
||||
} catch {
|
||||
Write-Log "Failed to verify top-level 'CLI': $_" "ERROR"
|
||||
exit 6
|
||||
}
|
||||
|
||||
# Install Playwright browsers (default: chromium) unless explicitly disabled
|
||||
if (-not $NoPlaywright) {
|
||||
Write-Log "Ensuring Playwright browsers are installed (browsers=$PlaywrightBrowsers)..."
|
||||
try {
|
||||
& $venvPython -c "import importlib; importlib.import_module('playwright')" 2>$null
|
||||
if ($LASTEXITCODE -ne 0) {
|
||||
Write-Log "'playwright' package not found in venv; installing via pip..."
|
||||
& $venvPython -m pip install playwright
|
||||
}
|
||||
} catch {
|
||||
Write-Log "Failed to check/install 'playwright' package: $_" "ERROR"
|
||||
}
|
||||
|
||||
try {
|
||||
if ($PlaywrightBrowsers -eq 'all') {
|
||||
Write-Log "Installing all Playwright browsers..."
|
||||
& $venvPython -m playwright install
|
||||
} else {
|
||||
$list = $PlaywrightBrowsers -split ','
|
||||
foreach ($b in $list) {
|
||||
$btrim = $b.Trim()
|
||||
if ($btrim) {
|
||||
Write-Log "Installing Playwright browser: $btrim"
|
||||
& $venvPython -m playwright install $btrim
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch {
|
||||
Write-Log "Playwright browser install failed: $_" "ERROR"
|
||||
}
|
||||
}
|
||||
|
||||
# Verify environment for known package conflicts (urllib3 compatibility)
|
||||
Write-Log "Verifying environment for known package conflicts (urllib3 compatibility)..."
|
||||
try {
|
||||
& $venvPython -c "import sys; from SYS.env_check import check_urllib3_compat; ok, msg = check_urllib3_compat(); print(msg); sys.exit(0 if ok else 2)"
|
||||
if ($LASTEXITCODE -ne 0) {
|
||||
Write-Log "Bootstrap detected a potentially broken 'urllib3' installation. See message above." "ERROR"
|
||||
Write-Log "Suggested fixes (activate the venv first):" "INFO"
|
||||
Write-Log " $ $venvPython -m pip uninstall urllib3-future -y" "INFO"
|
||||
Write-Log " $ $venvPython -m pip install --upgrade --force-reinstall urllib3" "INFO"
|
||||
Write-Log " $ $venvPython -m pip install niquests -U" "INFO"
|
||||
|
||||
function Get-SitePackages {
|
||||
param($python)
|
||||
try {
|
||||
$json = & $python -c "import site, sysconfig, json; p=[];
|
||||
try:
|
||||
p.extend(site.getsitepackages())
|
||||
except Exception:
|
||||
pass
|
||||
try:
|
||||
pp = sysconfig.get_paths().get('purelib')
|
||||
if pp:
|
||||
p.append(pp)
|
||||
except Exception:
|
||||
pass
|
||||
seen = []
|
||||
out = []
|
||||
for s in p:
|
||||
if s and s not in seen:
|
||||
seen.append(s)
|
||||
out.append(s)
|
||||
print(json.dumps(out))"
|
||||
return $json | ConvertFrom-Json
|
||||
} catch {
|
||||
return @()
|
||||
}
|
||||
}
|
||||
|
||||
function Find-InterferingPth {
|
||||
param($python)
|
||||
$pths = @()
|
||||
$sps = Get-SitePackages -python $python
|
||||
foreach ($sp in $sps) {
|
||||
if (Test-Path $sp) {
|
||||
Get-ChildItem -Path $sp -Filter *.pth -File -ErrorAction SilentlyContinue | ForEach-Object {
|
||||
$c = Get-Content -Path $_.FullName -ErrorAction SilentlyContinue | Out-String
|
||||
if ($c -match 'urllib3_future' -or $c -match 'urllib3-future') {
|
||||
$pths += $_.FullName
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return $pths
|
||||
}
|
||||
|
||||
# Helper to try removal and re-verify
|
||||
function RemovePthAndVerify {
|
||||
param($python, $paths)
|
||||
foreach ($p in $paths) { Remove-Item -Force $p -ErrorAction SilentlyContinue }
|
||||
try { & $python -m pip install --upgrade --force-reinstall urllib3 } catch { Write-Log "pip install failed: $_" "ERROR"; return $false }
|
||||
& $python -c "import sys; from SYS.env_check import check_urllib3_compat; ok, msg = check_urllib3_compat(); print(msg); sys.exit(0 if ok else 2)"
|
||||
return ($LASTEXITCODE -eq 0)
|
||||
}
|
||||
|
||||
if ($FixUrllib3) {
|
||||
Write-Log "Attempting automatic fix (--FixUrllib3)..." "INFO"
|
||||
try { & $venvPython -m pip uninstall urllib3-future -y } catch {}
|
||||
try { & $venvPython -m pip install --upgrade --force-reinstall urllib3 } catch { Write-Log "pip install failed: $_" "ERROR"; exit 7 }
|
||||
try { & $venvPython -m pip install niquests -U } catch { Write-Log "pip install niquests failed: $_" "ERROR" }
|
||||
& $venvPython -c "import sys; from SYS.env_check import check_urllib3_compat; ok, msg = check_urllib3_compat(); print(msg); sys.exit(0 if ok else 2)"
|
||||
if ($LASTEXITCODE -eq 0) {
|
||||
Write-Log "Success: urllib3 problems appear resolved; continuing." "INFO"
|
||||
} else {
|
||||
Write-Log "Initial automatic fix did not resolve the issue; searching for interfering .pth files..." "INFO"
|
||||
$pths = Find-InterferingPth -python $venvPython
|
||||
if ($pths.Count -eq 0) {
|
||||
Write-Log "No interfering .pth files found; aborting." "ERROR"
|
||||
exit 7
|
||||
}
|
||||
Write-Log ("Found interfering .pth files:`n" + ($pths -join "`n")) "ERROR"
|
||||
if ($RemovePth) {
|
||||
Write-Log "Removing .pth files as requested..." "INFO"
|
||||
if (RemovePthAndVerify -python $venvPython -paths $pths) {
|
||||
Write-Log "Success: urllib3 problems resolved after .pth removal; continuing." "INFO"
|
||||
} else {
|
||||
Write-Log "Automatic fix failed even after .pth removal; aborting." "ERROR"
|
||||
exit 7
|
||||
}
|
||||
} else {
|
||||
if ($Quiet) { Write-Log "Detected interfering .pth files but cannot prompt in quiet mode. Use -RemovePth to remove them automatically." "ERROR"; exit 7 }
|
||||
$ans = Read-Host "Remove these files now? (y/N)"
|
||||
if ($ans -eq 'y' -or $ans -eq 'Y') {
|
||||
if (RemovePthAndVerify -python $venvPython -paths $pths) {
|
||||
Write-Log "Success: urllib3 problems resolved after .pth removal; continuing." "INFO"
|
||||
} else {
|
||||
Write-Log "Automatic fix failed even after .pth removal; aborting." "ERROR"
|
||||
exit 7
|
||||
}
|
||||
} else {
|
||||
Write-Log "User declined to remove .pth files. Aborting." "ERROR"
|
||||
exit 7
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if ($Quiet) {
|
||||
Write-Log "Bootstrap detected a potentially broken 'urllib3' installation. Use -FixUrllib3 to attempt an automatic fix." "ERROR"
|
||||
exit 7
|
||||
}
|
||||
$ans = Read-Host "Attempt automatic fix now? (y/N)"
|
||||
if ($ans -eq 'y' -or $ans -eq 'Y') {
|
||||
$AutoFixInteractive = $true
|
||||
try { & $venvPython -m pip uninstall urllib3-future -y } catch {}
|
||||
try { & $venvPython -m pip install --upgrade --force-reinstall urllib3 } catch { Write-Log "pip install failed: $_" "ERROR"; exit 7 }
|
||||
try { & $venvPython -m pip install niquests -U } catch { Write-Log "pip install niquests failed: $_" "ERROR" }
|
||||
& $venvPython -c "import sys; from SYS.env_check import check_urllib3_compat; ok, msg = check_urllib3_compat(); print(msg); sys.exit(0 if ok else 2)"
|
||||
if ($LASTEXITCODE -eq 0) {
|
||||
Write-Log "Success: urllib3 problems appear resolved; continuing." "INFO"
|
||||
} else {
|
||||
Write-Log "Initial automatic fix did not resolve the issue; searching for interfering .pth files..." "INFO"
|
||||
$pths = Find-InterferingPth -python $venvPython
|
||||
if ($pths.Count -eq 0) {
|
||||
Write-Log "No interfering .pth files found; aborting." "ERROR"
|
||||
exit 7
|
||||
}
|
||||
Write-Log ("Found interfering .pth files:`n" + ($pths -join "`n")) "ERROR"
|
||||
if ($RemovePth -or $AutoFixInteractive -or $FixUrllib3) {
|
||||
Write-Log "Removing .pth files automatically..." "INFO"
|
||||
if (RemovePthAndVerify -python $venvPython -paths $pths) {
|
||||
Write-Log "Success: urllib3 problems resolved after .pth removal; continuing." "INFO"
|
||||
} else {
|
||||
Write-Log "Automatic fix failed even after .pth removal; aborting." "ERROR"
|
||||
exit 7
|
||||
}
|
||||
} else {
|
||||
$ans2 = Read-Host "Remove these files now? (y/N)"
|
||||
if ($ans2 -eq 'y' -or $ans2 -eq 'Y') {
|
||||
if (RemovePthAndVerify -python $venvPython -paths $pths) {
|
||||
Write-Log "Success: urllib3 problems resolved after .pth removal; continuing." "INFO"
|
||||
} else {
|
||||
Write-Log "Automatic fix failed even after .pth removal; aborting." "ERROR"
|
||||
exit 7
|
||||
}
|
||||
} else {
|
||||
Write-Log "User declined to remove .pth files. Aborting." "ERROR"
|
||||
exit 7
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
Write-Log "Aborting bootstrap to avoid leaving a broken environment." "ERROR"
|
||||
exit 7
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch {
|
||||
Write-Log "Failed to run environment verification: $_" "ERROR"
|
||||
}
|
||||
|
||||
Write-Log "Deno is already installed: $($denoCmd.Path)"
|
||||
} else {
|
||||
Write-Log "Installing Deno via official installer (https://deno.land)"
|
||||
try {
|
||||
try {
|
||||
irm https://deno.land/install.ps1 | iex
|
||||
} catch {
|
||||
iwr https://deno.land/install.ps1 -UseBasicParsing | iex
|
||||
}
|
||||
# Ensure common install locations are on PATH for this session
|
||||
$denoCandidatePaths = @(
|
||||
Join-Path $env:USERPROFILE ".deno\bin",
|
||||
Join-Path $env:LOCALAPPDATA "deno\bin"
|
||||
)
|
||||
foreach ($p in $denoCandidatePaths) {
|
||||
if (Test-Path $p) {
|
||||
if ($env:PATH -notmatch [regex]::Escape($p)) {
|
||||
$env:PATH = $env:PATH + ";" + $p
|
||||
}
|
||||
}
|
||||
}
|
||||
$v = & deno --version 2>$null
|
||||
if ($v) {
|
||||
Write-Log "Deno installed: $v"
|
||||
} else {
|
||||
Write-Log "Deno installer completed but 'deno' not found on PATH; you may need to restart your shell or add the Deno bin folder to PATH." "ERROR"
|
||||
}
|
||||
} catch {
|
||||
Write-Log "Deno install failed: $_" "ERROR"
|
||||
}
|
||||
}
|
||||
|
||||
# Shortcuts (Windows only)
|
||||
if ($IsWindowsPlatform) {
|
||||
if ($CreateDesktopShortcut -or $CreateStartMenuShortcut) {
|
||||
$wsh = New-Object -ComObject WScript.Shell
|
||||
$mmExe = Join-Path $venvFull "Scripts\mm.exe"
|
||||
$target = $null
|
||||
$args = ""
|
||||
if (Test-Path $mmExe) {
|
||||
$target = $mmExe
|
||||
} else {
|
||||
$target = $venvPython
|
||||
$args = "-m scripts.cli_entry"
|
||||
}
|
||||
if ($CreateDesktopShortcut) {
|
||||
$desk = [Environment]::GetFolderPath('Desktop')
|
||||
$link = Join-Path $desk "Medeia-Macina.lnk"
|
||||
Write-Log "Creating Desktop shortcut: $link"
|
||||
$sc = $wsh.CreateShortcut($link)
|
||||
$sc.TargetPath = $target
|
||||
$sc.Arguments = $args
|
||||
$sc.WorkingDirectory = $repoRoot
|
||||
$sc.IconLocation = "$target,0"
|
||||
$sc.Save()
|
||||
}
|
||||
if ($CreateStartMenuShortcut) {
|
||||
$start = Join-Path ([Environment]::GetFolderPath('ApplicationData')) 'Microsoft\Windows\Start Menu\Programs'
|
||||
$dir = Join-Path $start "Medeia-Macina"
|
||||
New-Item -ItemType Directory -Path $dir -Force | Out-Null
|
||||
$link2 = Join-Path $dir "Medeia-Macina.lnk"
|
||||
Write-Log "Creating Start Menu shortcut: $link2"
|
||||
$sc2 = $wsh.CreateShortcut($link2)
|
||||
$sc2.TargetPath = $target
|
||||
$sc2.Arguments = $args
|
||||
$sc2.WorkingDirectory = $repoRoot
|
||||
$sc2.IconLocation = "$target,0"
|
||||
$sc2.Save()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# Install global 'mm' launcher into the user's bin directory so it can be invoked from any shell.
|
||||
try {
|
||||
$globalBin = Join-Path $env:USERPROFILE 'bin'
|
||||
New-Item -ItemType Directory -Path $globalBin -Force | Out-Null
|
||||
$pythonCommand = $null
|
||||
if ($Python) {
|
||||
$pythonCommand = $Python
|
||||
} elseif (Get-Command py -ErrorAction SilentlyContinue) {
|
||||
$pythonCommand = "py"
|
||||
} elseif (Get-Command python -ErrorAction SilentlyContinue) {
|
||||
$pythonCommand = "python"
|
||||
}
|
||||
|
||||
$mmPs1 = Join-Path $globalBin 'mm.ps1'
|
||||
if (-not $pythonCommand) {
|
||||
throw "No Python 3 interpreter found. Install Python 3 and run the bootstrap again."
|
||||
}
|
||||
|
||||
$repo = $repoRoot
|
||||
|
||||
# PowerShell shim: use single-quoted here-string so literal PowerShell variables
|
||||
# (like $args) are not expanded by this script when writing the file.
|
||||
$ps1Text = @'
|
||||
Param([Parameter(ValueFromRemainingArguments=$true)] $args)
|
||||
$repo = "__REPO__"
|
||||
$venv = Join-Path $repo '.venv'
|
||||
$exe = Join-Path $venv 'Scripts\mm.exe'
|
||||
if (Test-Path $exe) { & $exe @args; exit $LASTEXITCODE }
|
||||
$py = Join-Path $venv 'Scripts\python.exe'
|
||||
if ($env:MM_DEBUG) {
|
||||
Write-Host "MM_DEBUG: diagnostics" -ForegroundColor Yellow
|
||||
if (Test-Path $py) { & $py -c "import sys,importlib,importlib.util,traceback; print('sys.executable:', sys.executable); print('sys.path (first 8):', sys.path[:8]);" }
|
||||
else { python -c "import sys,importlib,importlib.util,traceback; print('sys.executable:', sys.executable); print('sys.path (first 8):', sys.path[:8]);" }
|
||||
}
|
||||
if (Test-Path $py) { & $py -m scripts.cli_entry @args; exit $LASTEXITCODE }
|
||||
if (Test-Path (Join-Path $repo 'CLI.py')) { & python (Join-Path $repo 'CLI.py') @args; exit $LASTEXITCODE }
|
||||
# fallback
|
||||
python -m scripts.cli_entry @args
|
||||
'@
|
||||
# Thin wrapper: prefer the canonical Python bootstrap installer
|
||||
$scriptDir = Split-Path -Parent $MyInvocation.MyCommand.Path
|
||||
$repo = (Resolve-Path (Join-Path $scriptDir "..")).Path
|
||||
$venvPy = Join-Path $repo '.venv\Scripts\python.exe'
|
||||
|
||||
# Normalize incoming quiet flag (-Quiet) into -q for the Python script
|
||||
$forwardArgs = @()
|
||||
foreach ($a in $args) {
|
||||
if ($a -eq '-Quiet') { $forwardArgs += '-q' } else { $forwardArgs += $a }
|
||||
if ($pythonCommand -eq "py") {
|
||||
& py -3 $bootstrapPath @pythonArgs
|
||||
} else {
|
||||
& $pythonCommand $bootstrapPath @pythonArgs
|
||||
}
|
||||
$exitCode = $LASTEXITCODE
|
||||
} finally {
|
||||
if ($temporaryBootstrap -and (Test-Path $bootstrapPath)) {
|
||||
Remove-Item -LiteralPath $bootstrapPath -Force -ErrorAction SilentlyContinue
|
||||
}
|
||||
}
|
||||
|
||||
# Debug helper
|
||||
if ($env:MM_DEBUG) { Write-Host "MM_DEBUG: invoking python installer with args: $forwardArgs" -ForegroundColor Yellow }
|
||||
|
||||
if (Test-Path $venvPy) {
|
||||
& $venvPy (Join-Path $repo 'scripts\bootstrap.py') --no-delegate @forwardArgs
|
||||
exit $LASTEXITCODE
|
||||
}
|
||||
|
||||
# Fall back to any system Python (py -3 -> python3 -> python)
|
||||
if (Get-Command -Name py -ErrorAction SilentlyContinue) {
|
||||
& py -3 (Join-Path $repo 'scripts\bootstrap.py') --no-delegate @forwardArgs
|
||||
exit $LASTEXITCODE
|
||||
}
|
||||
if (Get-Command -Name python3 -ErrorAction SilentlyContinue) {
|
||||
& python3 (Join-Path $repo 'scripts\bootstrap.py') --no-delegate @forwardArgs
|
||||
exit $LASTEXITCODE
|
||||
}
|
||||
if (Get-Command -Name python -ErrorAction SilentlyContinue) {
|
||||
& python (Join-Path $repo 'scripts\bootstrap.py') --no-delegate @forwardArgs
|
||||
exit $LASTEXITCODE
|
||||
}
|
||||
|
||||
Write-Host 'Error: no suitable Python 3 interpreter found. Please install Python 3 or use the venv.' -ForegroundColor Red
|
||||
exit 127
|
||||
exit $exitCode
|
||||
+13
-1
@@ -315,7 +315,19 @@ def _install_mpv() -> int:
|
||||
# Windows: use winget (built-in package manager)
|
||||
if shutil.which("winget"):
|
||||
print("Installing MPV via winget...")
|
||||
run(["winget", "install", "--id=mpv.net", "-e"])
|
||||
run(
|
||||
[
|
||||
"winget",
|
||||
"install",
|
||||
"--id=mpv.net",
|
||||
"-e",
|
||||
"--source",
|
||||
"winget",
|
||||
"--accept-source-agreements",
|
||||
"--accept-package-agreements",
|
||||
"--silent",
|
||||
]
|
||||
)
|
||||
else:
|
||||
print(
|
||||
"MPV not found and winget not available.\n"
|
||||
|
||||
@@ -120,12 +120,8 @@ packages = [
|
||||
"cmdlet",
|
||||
"cmdnat",
|
||||
"API",
|
||||
"Store",
|
||||
"PluginCore",
|
||||
"SYS",
|
||||
"tool",
|
||||
"TUI",
|
||||
"MPV",
|
||||
]
|
||||
package-dir = {"" = ".."}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user