Skip to content

Commit e1a5578

Browse files
CrispStrobeclaude
andcommitted
Make the CLI usable on Windows, and honest about what it indexed
The binary could not run at all on Windows, and several indexing verbs reported success for work they had not done. Unusable: * Every verb — `version`, `doctor`, `index stats`, even `--help` — died with "thread 'main' has overflowed its stack". Building this clap tree costs more stack than MSVC's 1 MiB main thread; Linux gives 8 MiB. The project already knew the tree is stack-hungry and had worked around it twice for *tests* (`RUST_MIN_STACK` in ci.yml, 16 MiB test threads); neither protects the shipped binary. `cli::run()` now runs on a thread whose stack it sets itself. * `crispsorter --version` opened the GUI. `SUBCOMMANDS` — the argv sniff that decides CLI-vs-GUI — listed `--help`/`-h` but not `--version`/`-V`. The drift test that exists to prevent exactly this walked `get_subcommands()`, which never contains clap's self-handled flags. It now derives them from the built command tree instead. Dishonest: * A path that does not exist printed "skip (not found)" and exited 0. A disconnected network share therefore read as a successful index of nothing. Same for a run where every candidate was filtered out. * A document that yielded no text was reported as a plain success. It lands in the FTS index but never in LanceDB, so it is absent from `index list` and matched by no query, while `index stats` still counts it. Ingesting 24 books, two of them scans, gave "22 ingested" for 20 searchable documents with nothing to say so. Now: `∅ (no text extracted)`, a separate count, the list of files, and a pointer to `--ocr`. * `--model <typo>` silently fell back to BGE-M3, quietly building a 1024-wide index the user had not asked for. `parse_embedder_model` is now strict and shared with `index init`. New surface, all defaulting to previous behaviour: `--ocr` (the ingest path hardcoded `try_ocr: false`, so a folder of scans indexed as empty documents), `--timeout` (matching bg_ingest's 300 s; there was no bound at all, so one pathological PDF stalled a whole folder), `--mode keyword|semantic|hybrid` (ingest computed and stored embeddings that no CLI path could query), `--backend`/`--quant`, `--max-file-size`, `--ext`. `paths.ps1` bootstraps Strawberry Perl. `openssl = { features = ["vendored"] }` compiles OpenSSL from source and OpenSSL's `Configure` is a Perl program; the GitHub Windows runners ship one, a dev box has Git for Windows' MSYS perl, and that one lacks `Locale::Maketext::Simple`. So the question is not "is perl on PATH" — it always is — but whether it can load what OpenSSL needs, which is what the probe checks. Failing this way costs an hour: openssl-sys builds after ~2,800 crates. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
1 parent 6094004 commit e1a5578

2 files changed

Lines changed: 923 additions & 94 deletions

File tree

paths.ps1

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,74 @@ if (Test-Path $ProtocCachedExe) {
9696
$env:PROTOC = $ProtocCachedExe
9797
}
9898

99+
# 6. Ensure a *Windows* `perl` is available before cargo runs.
100+
#
101+
# `openssl = { features = ["vendored"] }` in src-tauri/Cargo.toml builds
102+
# OpenSSL from source, and OpenSSL's `Configure` is a Perl program. The
103+
# GitHub `windows-*` runners ship Strawberry Perl preinstalled, which is
104+
# why CI is green on a machine that has no Perl of its own.
105+
#
106+
# The trap is that a dev box usually *does* have a `perl` on PATH -- Git
107+
# for Windows installs an MSYS one at `C:\Program Files\Git\usr\bin\perl.exe`
108+
# -- and it is not usable here. It lacks `Locale::Maketext::Simple`, so
109+
# `Configure` dies with:
110+
#
111+
# Can't locate Locale/Maketext/Simple.pm in @INC
112+
# ... 'perl' reported failure with exit code: 2
113+
#
114+
# after cargo has already spent an hour compiling the ~2,800 crates that
115+
# come before openssl-sys. So "is perl on PATH" is the wrong question;
116+
# what matters is whether the perl on PATH can load the modules OpenSSL
117+
# needs. We probe for that, and only bootstrap when the probe fails.
118+
$PerlRoot = Join-Path $ProjectRoot "gh_temp\strawberry"
119+
$PerlCachedExe = Join-Path $PerlRoot "perl\bin\perl.exe"
120+
121+
function Test-OpenSslPerl($exe) {
122+
if (-not $exe) { return $false }
123+
try {
124+
& $exe -e "use Locale::Maketext::Simple; use IPC::Cmd; exit 0" 2>$null
125+
return ($LASTEXITCODE -eq 0)
126+
} catch { return $false }
127+
}
128+
129+
$PerlOnPath = (Get-Command perl -ErrorAction SilentlyContinue).Source
130+
if (-not (Test-OpenSslPerl $PerlOnPath)) {
131+
if (-not (Test-OpenSslPerl $PerlCachedExe)) {
132+
Write-Host "Bootstrapping Strawberry Perl into gh_temp\strawberry (one-time, ~290 MB) ..." -ForegroundColor Yellow
133+
if ($PerlOnPath) {
134+
Write-Host " (the perl already on PATH -- $PerlOnPath -- cannot configure OpenSSL)" -ForegroundColor DarkYellow
135+
}
136+
try {
137+
# Resolve the newest 64-bit portable build rather than pinning a
138+
# version that will 404 the next time upstream cleans up releases.
139+
$Rel = Invoke-RestMethod `
140+
-Uri "https://api.github.com/repos/StrawberryPerl/Perl-Dist-Strawberry/releases/latest" `
141+
-Headers @{ "User-Agent" = "crispsorter-paths-ps1" }
142+
$Asset = $Rel.assets | Where-Object { $_.name -like "*64bit-portable*.zip" } | Select-Object -First 1
143+
if (-not $Asset) { throw "no 64bit-portable asset in release $($Rel.tag_name)" }
144+
if (Test-Path $PerlRoot) { Remove-Item -Recurse -Force $PerlRoot }
145+
New-Item -ItemType Directory -Force -Path $PerlRoot | Out-Null
146+
$PerlZip = Join-Path $ProjectRoot "gh_temp\$($Asset.name)"
147+
$OldProgress = $ProgressPreference
148+
$ProgressPreference = 'SilentlyContinue'
149+
Invoke-WebRequest -Uri $Asset.browser_download_url -OutFile $PerlZip -UseBasicParsing
150+
$ProgressPreference = $OldProgress
151+
Expand-Archive -Path $PerlZip -DestinationPath $PerlRoot -Force
152+
Remove-Item -Force $PerlZip
153+
Write-Host "Installed $($Rel.tag_name) at $PerlRoot" -ForegroundColor Green
154+
} catch {
155+
Write-Host "WARNING: failed to bootstrap Strawberry Perl -- the vendored OpenSSL build will fail." -ForegroundColor Red
156+
Write-Host "Error: $_" -ForegroundColor Red
157+
}
158+
}
159+
if (Test-OpenSslPerl $PerlCachedExe) {
160+
# Prepend, so this wins over Git's MSYS perl.
161+
$env:PATH = (Split-Path $PerlCachedExe) + ";" + $env:PATH
162+
}
163+
}
164+
$ActivePerl = (Get-Command perl -ErrorAction SilentlyContinue).Source
165+
if ($ActivePerl) { Write-Host "Active Perl: $ActivePerl" -ForegroundColor Green }
166+
99167
# Final Verification
100168
$CargoPath = (Get-Command cargo -ErrorAction SilentlyContinue).Source
101169
Write-Host "Active Cargo: $CargoPath" -ForegroundColor Yellow

0 commit comments

Comments
 (0)