install: close six WoA/WSL review gaps in provisioning, shortcuts, uninstall
Review round on the Windows-on-ARM + NVIDIA WSL2 path; each item reproduced against the live scripts before fixing. provision_llama_cuda.sh now serializes with install_llama_prebuilt.py on the same <parent>/.<name>.install.lock file (its filelock backend is flock(2), so shell flock interoperates; append-mode open so the Python O_EXCL fallback's PID file is never truncated). The detached background builder could otherwise race an installer rerun or `unsloth studio update`, both of which mv/rm -rf inside the llama.cpp dir. Losing the 2h wait exits 0: another provisioner is already doing the job. The step-0 early-skip trusted a co-located libggml-cuda.so alone, which wrongly skips one case: an in-place rebuild interrupted after the .so links but before llama-server relinks leaves new .so + old CPU server. A completion stamp (build/bin/.unsloth-cuda-ok) written only after the script's own final CUDA check closes that window; skip now requires ldd evidence or the stamp. The rejected functional --list-devices probe stays rejected: the stamp does not gamble thermals on an env-fragile probe. The WSL shortcut skip (install.ps1 owns the canonical WoA .lnk) was only a transient env var, so the first `unsloth studio update`, whose wsl.exe shim carries no env into install.sh --shortcuts-only, recreated the duplicate blank-icon shortcut. The skip is now also persisted as /root/.unsloth/.skip-wsl-windows-shortcut, checked by install.sh and removed with the install by both uninstallers. --with-llama-cpp-dir (and UNSLOTH_LOCAL_LLAMA_CPP_DIR) were parsed but silently ignored on the WSL fallback path, which builds its own llama.cpp inside the distro. Reject with guidance (UNSLOTH_LLAMA_TAG / UNSLOTH_LLAMA_PR pin the WSL-side build), mirroring the --local reject. uninstall.sh's Windows shortcut sweep only removed wsl.exe-target .lnks, so the WoA fallback shortcuts (powershell.exe + launch-studio-wsl.ps1) survived while their launcher dir was deleted, leaving dangling shortcuts. The owner-matched cleanup now removes them first. uninstall.ps1 swept every "Unsloth Studio (*.lnk" as legacy, but install.sh creates exactly that per-distro name for current WSL installs, and the WSL cleanup below only removes evidenced distros. The sweep now keeps a live wsl.exe launcher whose distro is not in the same evidence set, so a surviving WSL install keeps its shortcut; everything else is still swept. Verified: bash -n on all three shell scripts, PowerShell AST parse on both ps1 files, flock mutual-exclusion and stamp skip/rebuild decisions exercised standalone, and the uninstall icon suites (sh + ps1) pass. The test_install_host_defaults.sh failure pre-exists on the branch merge base.
This commit is contained in:
parent
7efe4c7107
commit
9ae5565803
5 changed files with 89 additions and 12 deletions
12
install.ps1
12
install.ps1
|
|
@ -2111,6 +2111,13 @@ exit 0
|
|||
if ($envOverride) {
|
||||
substep "note: $envOverrideVar='$envOverride' is not used for the Windows-on-ARM WSL install -- Studio installs inside WSL at /root/.unsloth." "Yellow"
|
||||
}
|
||||
# --with-llama-cpp-dir names a Windows-side llama.cpp, but this install runs
|
||||
# llama.cpp inside WSL2 and would silently ignore the user's explicit binary
|
||||
# choice. Reject like --local and point at the supported WSL-side pins.
|
||||
if ($WithLlamaCppDir -or $env:UNSLOTH_LOCAL_LLAMA_CPP_DIR) {
|
||||
Restore-StudioVenvRollback
|
||||
return (Exit-InstallFailure "--with-llama-cpp-dir / UNSLOTH_LOCAL_LLAMA_CPP_DIR can't be honored on Windows-on-ARM + NVIDIA: llama.cpp runs inside WSL2 and can't use a Windows path. Remove it, or pin the WSL-side build with UNSLOTH_LLAMA_TAG or UNSLOTH_LLAMA_PR instead." 1)
|
||||
}
|
||||
|
||||
$wslReady = $false
|
||||
if (Get-Command wsl.exe -ErrorAction SilentlyContinue) {
|
||||
|
|
@ -2208,7 +2215,10 @@ exit 0
|
|||
# install.ps1 owns the WoA shortcut (one canonical "Unsloth Studio.lnk" with a
|
||||
# %USERPROFILE%\.unsloth icon that renders on WoA). Tell install.sh to skip its own
|
||||
# WSL .lnk so we don't get a duplicate whose %LOCALAPPDATA% icon renders blank.
|
||||
$_fwdEnv += 'export UNSLOTH_SKIP_WSL_WINDOWS_SHORTCUT=1; '
|
||||
# Persist the skip as a marker file too: `unsloth studio update` reruns
|
||||
# install.sh --shortcuts-only through the wsl.exe shim, which carries no env,
|
||||
# so without the marker the first update would recreate the duplicate .lnk.
|
||||
$_fwdEnv += 'export UNSLOTH_SKIP_WSL_WINDOWS_SHORTCUT=1; mkdir -p /root/.unsloth; touch /root/.unsloth/.skip-wsl-windows-shortcut; '
|
||||
if ($_instRef -eq 'main') {
|
||||
$wslInstall = $_fwdEnv + 'export DEBIAN_FRONTEND=noninteractive UNSLOTH_WSL_LLAMA_DEFERRED=1; apt-get update -y >/dev/null; apt-get install -y build-essential cmake git curl pciutils libcurl4-openssl-dev >/dev/null; curl -fsSL https://unsloth.ai/install.sh | sh'
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -1234,7 +1234,8 @@ STUB_EOF
|
|||
fi
|
||||
_css_created=1
|
||||
|
||||
elif [ "$_css_os" = "wsl" ] && [ "${UNSLOTH_SKIP_WSL_WINDOWS_SHORTCUT:-0}" != "1" ]; then
|
||||
elif [ "$_css_os" = "wsl" ] && [ "${UNSLOTH_SKIP_WSL_WINDOWS_SHORTCUT:-0}" != "1" ] \
|
||||
&& [ ! -f "$HOME/.unsloth/.skip-wsl-windows-shortcut" ]; then
|
||||
# ── WSL: create Windows Desktop and Start Menu shortcuts ──
|
||||
# Detect current WSL distro for targeted shortcut
|
||||
_css_distro="${WSL_DISTRO_NAME:-}"
|
||||
|
|
|
|||
|
|
@ -399,17 +399,50 @@ function Uninstall-UnslothStudio {
|
|||
}
|
||||
|
||||
# ── Remove desktop and Start Menu shortcuts ──
|
||||
# Canonical name is "Unsloth Studio.lnk"; also sweep legacy distro-suffixed names
|
||||
# ("Unsloth Studio (WSL - <distro>).lnk") left by pre-release dev builds.
|
||||
# Canonical name is "Unsloth Studio.lnk". Distro-suffixed names
|
||||
# ("Unsloth Studio (WSL - <distro>).lnk") belong to per-distro WSL installs, which
|
||||
# the WSL-fallback section below only cleans for evidenced distros (env var,
|
||||
# wsl-distro.txt marker, or the legacy ARM64 probe) -- scope this sweep to the
|
||||
# same set so a surviving WSL install keeps its launcher. Anything that is not a
|
||||
# live wsl.exe launcher (pre-release leftovers) is still swept.
|
||||
_Step "Removing desktop and Start Menu shortcuts..."
|
||||
$_scCands = @()
|
||||
if ($env:UNSLOTH_WSL_DISTRO) { $_scCands += $env:UNSLOTH_WSL_DISTRO }
|
||||
try {
|
||||
if ($env:LOCALAPPDATA) {
|
||||
$_scDf = Join-Path (Join-Path $env:LOCALAPPDATA "Unsloth") "wsl-distro.txt"
|
||||
if (Test-Path -LiteralPath $_scDf) {
|
||||
$_scRd = (Get-Content -LiteralPath $_scDf -ErrorAction SilentlyContinue | Select-Object -First 1)
|
||||
if ($_scRd -and $_scRd.Trim()) { $_scCands += $_scRd.Trim() }
|
||||
}
|
||||
}
|
||||
} catch { }
|
||||
if ((-not $_scCands) -and ($env:PROCESSOR_ARCHITECTURE -eq 'ARM64')) {
|
||||
$_scCands = @('Ubuntu', 'Ubuntu-24.04', 'Ubuntu-22.04', 'Debian')
|
||||
}
|
||||
$_scWs = $null
|
||||
try { $_scWs = New-Object -ComObject WScript.Shell } catch { }
|
||||
$shortcutDirs = @()
|
||||
try { $d = [Environment]::GetFolderPath("Desktop"); if ($d) { $shortcutDirs += $d } } catch { }
|
||||
if ($env:APPDATA) { $shortcutDirs += (Join-Path $env:APPDATA "Microsoft\Windows\Start Menu\Programs") }
|
||||
foreach ($dir in $shortcutDirs) {
|
||||
if (-not (Test-Path -LiteralPath $dir)) { continue }
|
||||
_RemovePath (Join-Path $dir "Unsloth Studio.lnk")
|
||||
Get-ChildItem -LiteralPath $dir -Filter "Unsloth Studio (*.lnk" -ErrorAction SilentlyContinue |
|
||||
ForEach-Object { _RemovePath $_.FullName }
|
||||
Get-ChildItem -LiteralPath $dir -Filter "Unsloth Studio (*.lnk" -ErrorAction SilentlyContinue | ForEach-Object {
|
||||
$_scKeep = $false
|
||||
if ($_scWs) {
|
||||
try {
|
||||
$_sc = $_scWs.CreateShortcut($_.FullName)
|
||||
if ("$($_sc.TargetPath) $($_sc.Arguments)" -match "wsl\.exe") {
|
||||
$_scD = $null
|
||||
if ($_sc.Arguments -match '-d\s+"?([^"\s]+)"?') { $_scD = $Matches[1] }
|
||||
elseif ($_.Name -match '^Unsloth Studio \(WSL - (.+)\)\.lnk$') { $_scD = $Matches[1] }
|
||||
if ($_scD -and ($_scCands -notcontains $_scD)) { $_scKeep = $true }
|
||||
}
|
||||
} catch { }
|
||||
}
|
||||
if (-not $_scKeep) { _RemovePath $_.FullName }
|
||||
}
|
||||
}
|
||||
# Invalidate the Win11 Start Menu tile cache so the removed shortcut's tile
|
||||
# disappears promptly instead of lingering stale (mirrors install.ps1's
|
||||
|
|
|
|||
|
|
@ -320,6 +320,16 @@ case "$_os" in
|
|||
$shim = (Join-Path $ud "bin").TrimEnd("\","/");
|
||||
$up = [Environment]::GetEnvironmentVariable("Path","User");
|
||||
if ($up) { [Environment]::SetEnvironmentVariable("Path", (($up -split ";" | Where-Object { $_ -and ($_.TrimEnd("\","/") -ine $shim) }) -join ";"), "User") }
|
||||
# The WoA-fallback shortcuts target powershell.exe + launch-studio-wsl.ps1
|
||||
# (not wsl.exe), so the sweep above keeps them; remove them here before
|
||||
# their launcher dir is deleted or they would dangle.
|
||||
foreach ($d in $dirs) {
|
||||
if (-not $d -or -not (Test-Path -LiteralPath $d)) { continue }
|
||||
$l = Join-Path $d "Unsloth Studio.lnk";
|
||||
if (Test-Path -LiteralPath $l) {
|
||||
try { $sc2 = $ws.CreateShortcut($l); if ($sc2.Arguments -match "launch-studio-wsl\.ps1") { Remove-Item -LiteralPath $l -Force -ErrorAction SilentlyContinue } } catch { }
|
||||
}
|
||||
}
|
||||
if (Test-Path -LiteralPath $ud) { Remove-Item -LiteralPath $ud -Recurse -Force -ErrorAction SilentlyContinue }
|
||||
}
|
||||
# Keep the shared icon while any Unsloth shortcut still uses it (native
|
||||
|
|
|
|||
|
|
@ -13,6 +13,22 @@ LLAMA_DIR="${UNSLOTH_LLAMA_CPP_PATH:-$HOME/.unsloth/llama.cpp}"
|
|||
SERVER="$LLAMA_DIR/build/bin/llama-server"
|
||||
log() { printf ' - %s\n' "$*"; }
|
||||
|
||||
# Serialize against install_llama_prebuilt.py (same lock file as its
|
||||
# install_lock_path: <parent>/.<name>.install.lock; its filelock backend is
|
||||
# flock(2), so this interoperates) and against a second copy of this script: the
|
||||
# detached background builder can otherwise race an installer rerun or `unsloth
|
||||
# studio update`, both of which mv/rm -rf inside $LLAMA_DIR. Append-mode open so
|
||||
# the Python O_EXCL fallback's PID file is never truncated. 2h cap matches a
|
||||
# worst-case source build; losing the wait means another provisioner is already
|
||||
# doing this exact job, so exiting 0 is correct.
|
||||
_LOCK_DIR="$(dirname "$LLAMA_DIR")"
|
||||
mkdir -p "$_LOCK_DIR" 2>/dev/null
|
||||
if command -v flock >/dev/null 2>&1; then
|
||||
if exec 9>>"$_LOCK_DIR/.$(basename "$LLAMA_DIR").install.lock" 2>/dev/null; then
|
||||
flock -w 7200 9 || { log "another llama.cpp install holds the lock; skipping"; exit 0; }
|
||||
fi
|
||||
fi
|
||||
|
||||
# Detect CUDA two ways: monolithic (libggml-cuda in ldd) or split (dlopen-ed
|
||||
# libggml-cuda.so* beside the binary, missed by ldd). CPU-only builds ship no
|
||||
# libggml-cuda.so, so its presence is the reliable signal.
|
||||
|
|
@ -23,18 +39,24 @@ is_cuda_server() {
|
|||
return 1
|
||||
}
|
||||
|
||||
# 0. Already provisioned? A co-located libggml-cuda.so* is the trusted signal: the
|
||||
# prebuilt resolver validates the server it installs, and a *source* build that gets
|
||||
# interrupted is caught by the build-failure wipe+rebuild below (section 6), so the
|
||||
# early-skip can rely on the structural check. We deliberately do NOT run a functional
|
||||
# 0. Already provisioned? Skip when the server links libggml-cuda directly (ldd)
|
||||
# or when a co-located libggml-cuda.so* is paired with the completion stamp this
|
||||
# script writes after its own final CUDA check. The stamp closes the one gap in
|
||||
# the structural check: an in-place rebuild interrupted after libggml-cuda.so is
|
||||
# linked but before llama-server relinks leaves new .so + old CPU server, which
|
||||
# the bare .so test would wrongly skip. We deliberately do NOT run a functional
|
||||
# `--list-devices` probe here: this script runs in a stripped-down detached shell whose
|
||||
# loader path can miss /usr/lib/wsl/lib, so the CUDA backend may fail to enumerate even
|
||||
# on a perfectly good server -- and a false negative would wipe a validated build and
|
||||
# trigger a needless, thermally-dangerous source rebuild on the NVIDIA-ARM laptops this
|
||||
# targets. Trust the .so; never gamble the machine's thermals on an env-fragile probe.
|
||||
_CUDA_STAMP="$LLAMA_DIR/build/bin/.unsloth-cuda-ok"
|
||||
if is_cuda_server "$SERVER"; then
|
||||
log "CUDA llama-server already present: $SERVER"
|
||||
exit 0
|
||||
if ldd "$SERVER" 2>/dev/null | grep -qi 'libggml-cuda' || [ -e "$_CUDA_STAMP" ]; then
|
||||
log "CUDA llama-server already present: $SERVER"
|
||||
exit 0
|
||||
fi
|
||||
log "CUDA .so present but the build never stamped complete (interrupted relink?); rebuilding"
|
||||
fi
|
||||
|
||||
# 1. Require an NVIDIA GPU (this script is only meaningful with one).
|
||||
|
|
@ -259,6 +281,7 @@ _cmake_build_extras
|
|||
_restore_build
|
||||
|
||||
if is_cuda_server "$SERVER"; then
|
||||
: > "$_CUDA_STAMP" 2>/dev/null || true
|
||||
log "CUDA llama-server ready: $SERVER"
|
||||
[ -n "$_LLAMA_BAK" ] && rm -rf "$_LLAMA_BAK" 2>/dev/null
|
||||
elif [ -x "$SERVER" ]; then
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue