From fa03f1e63beea89013ffb9128c8c3822a60e77fd Mon Sep 17 00:00:00 2001 From: Nose Date: Fri, 10 Jul 2026 21:17:41 -0700 Subject: [PATCH] update instalelr --- readme.md | 23 +- scripts/bootstrap.ps1 | 614 +++++------------------------------------ scripts/bootstrap.py | 14 +- scripts/pyproject.toml | 4 - 4 files changed, 90 insertions(+), 565 deletions(-) diff --git a/readme.md b/readme.md index 2bf4ab2..2bd5426 100644 --- a/readme.md +++ b/readme.md @@ -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. diff --git a/scripts/bootstrap.ps1 b/scripts/bootstrap.ps1 index d4ffb33..39a7262 100644 --- a/scripts/bootstrap.ps1 +++ b/scripts/bootstrap.ps1 @@ -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 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 \ No newline at end of file diff --git a/scripts/bootstrap.py b/scripts/bootstrap.py index 54a578d..4121657 100644 --- a/scripts/bootstrap.py +++ b/scripts/bootstrap.py @@ -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" diff --git a/scripts/pyproject.toml b/scripts/pyproject.toml index 29c3a93..406ebe1 100644 --- a/scripts/pyproject.toml +++ b/scripts/pyproject.toml @@ -120,12 +120,8 @@ packages = [ "cmdlet", "cmdnat", "API", - "Store", "PluginCore", "SYS", - "tool", - "TUI", - "MPV", ] package-dir = {"" = ".."}