72 lines
7.0 KiB
PowerShell
72 lines
7.0 KiB
PowerShell
if ($operation -ne 'rg') { Fail ('unsupported Windows fs operation: ' + $operation) 2 }
|
|
|
|
$ignoreCase = $false; $fixed = $false; $filesOnly = $false; $endOptions = $false
|
|
$maxCount = [int]$rgPolicy.maxMatches; $maxFiles = [int]$rgPolicy.maxFiles; $maxBytes = [int]$rgPolicy.maxBytesPerFile; $timeoutMs = [int]$rgPolicy.timeoutMs
|
|
$paths = [Collections.Generic.List[string]]::new(); $globs = [Collections.Generic.List[string]]::new(); $patterns = [Collections.Generic.List[string]]::new()
|
|
for ($i = 0; $i -lt $toolArgs.Count; $i++) {
|
|
$arg = $toolArgs[$i]
|
|
if (-not $endOptions -and $arg -eq '--') { $endOptions = $true; continue }
|
|
if (-not $endOptions -and $arg -in @('-i', '--ignore-case')) { $ignoreCase = $true; continue }
|
|
if (-not $endOptions -and $arg -in @('-F', '--fixed-strings')) { $fixed = $true; continue }
|
|
if (-not $endOptions -and $arg -in @('-n', '--line-number')) { continue }
|
|
if (-not $endOptions -and $arg -eq '--files') { $filesOnly = $true; continue }
|
|
if (-not $endOptions -and $arg -in @('-e', '--regexp')) { $i += 1; if ($i -ge $toolArgs.Count) { Fail ($arg + ' requires a value') 2 }; $patterns.Add($toolArgs[$i]); continue }
|
|
if (-not $endOptions -and $arg.StartsWith('--regexp=')) { $patterns.Add($arg.Substring(9)); continue }
|
|
if (-not $endOptions -and $arg -in @('-g', '--glob')) { $i += 1; if ($i -ge $toolArgs.Count) { Fail ($arg + ' requires a value') 2 }; $globs.Add($toolArgs[$i]); continue }
|
|
if (-not $endOptions -and $arg.StartsWith('--glob=')) { $globs.Add($arg.Substring(7)); continue }
|
|
if (-not $endOptions -and $arg -in @('-m', '--max-count')) { $i += 1; if ($i -ge $toolArgs.Count) { Fail ($arg + ' requires a value') 2 }; $maxCount = Parse-NonNegativeInt $arg $toolArgs[$i] 10000; continue }
|
|
if (-not $endOptions -and $arg.StartsWith('-m') -and $arg.Length -gt 2) { $maxCount = Parse-NonNegativeInt '-m' $arg.Substring(2) 10000; continue }
|
|
if (-not $endOptions -and $arg.StartsWith('--max-count=')) { $maxCount = Parse-NonNegativeInt '--max-count' $arg.Substring(12) 10000; continue }
|
|
if (-not $endOptions -and $arg -eq '--max-files') { $i += 1; if ($i -ge $toolArgs.Count) { Fail '--max-files requires a value' 2 }; $maxFiles = Parse-NonNegativeInt '--max-files' $toolArgs[$i] 50000; continue }
|
|
if (-not $endOptions -and $arg.StartsWith('--max-files=')) { $maxFiles = Parse-NonNegativeInt '--max-files' $arg.Substring(12) 50000; continue }
|
|
if (-not $endOptions -and $arg -eq '--max-bytes') { $i += 1; if ($i -ge $toolArgs.Count) { Fail '--max-bytes requires a value' 2 }; $maxBytes = Parse-NonNegativeInt '--max-bytes' $toolArgs[$i] 16777216; continue }
|
|
if (-not $endOptions -and $arg.StartsWith('--max-bytes=')) { $maxBytes = Parse-NonNegativeInt '--max-bytes' $arg.Substring(12) 16777216; continue }
|
|
if (-not $endOptions -and $arg -eq '--timeout-ms') { $i += 1; if ($i -ge $toolArgs.Count) { Fail '--timeout-ms requires a value' 2 }; $timeoutMs = Parse-NonNegativeInt '--timeout-ms' $toolArgs[$i] 60000; continue }
|
|
if (-not $endOptions -and $arg.StartsWith('--timeout-ms=')) { $timeoutMs = Parse-NonNegativeInt '--timeout-ms' $arg.Substring(13) 60000; continue }
|
|
if (-not $endOptions -and $arg.StartsWith('-')) { Fail ('unsupported rg option on Windows route: ' + $arg + '; supported: --files -e/--regexp -g/--glob -i -F -n -m/--max-count --max-files --max-bytes --timeout-ms') 2 }
|
|
if ($filesOnly) { $paths.Add($arg) } elseif ($patterns.Count -eq 0) { $patterns.Add($arg) } else { $paths.Add($arg) }
|
|
}
|
|
if (-not $filesOnly -and $patterns.Count -eq 0) { Fail 'rg requires a pattern on Windows routes (or use --files)' 2 }
|
|
if ($paths.Count -eq 0) { $paths.Add('.') }
|
|
|
|
$nativeRg = Get-Command rg.exe -ErrorAction SilentlyContinue | Select-Object -First 1
|
|
if ($null -eq $nativeRg) { Fail 'rg.exe is unavailable on this Windows plane; install ripgrep or use ps with a reviewed PowerShell search' 127 }
|
|
if ($null -ne $nativeRg) {
|
|
function Quote-NativeArg([string]$Value) {
|
|
if ($Value.Contains('"')) { Fail 'rg argument contains a quote; use ps for shell-reviewed quoting' 2 }
|
|
if ($Value -match '\s') { return '"' + $Value + '"' }
|
|
return $Value
|
|
}
|
|
$nativeArgs = [Collections.Generic.List[string]]::new()
|
|
$nativeArgs.Add('--color=never'); $nativeArgs.Add('--no-heading'); $nativeArgs.Add('--line-number'); $nativeArgs.Add('--with-filename')
|
|
$nativeArgs.Add('--max-filesize'); $nativeArgs.Add([string]$maxBytes)
|
|
if ($ignoreCase) { $nativeArgs.Add('--ignore-case') }
|
|
if ($fixed) { $nativeArgs.Add('--fixed-strings') }
|
|
foreach ($glob in $globs) { $nativeArgs.Add('--glob'); $nativeArgs.Add($glob) }
|
|
if ($filesOnly) { $nativeArgs.Add('--files') } else { foreach ($item in $patterns) { $nativeArgs.Add('--regexp'); $nativeArgs.Add($item) } }
|
|
foreach ($raw in $paths) { $nativeArgs.Add((Resolve-UnideskPath $raw)) }
|
|
$startInfo = [Diagnostics.ProcessStartInfo]::new()
|
|
$startInfo.FileName = $nativeRg.Source
|
|
$startInfo.Arguments = [string]::Join(' ', @($nativeArgs | ForEach-Object { Quote-NativeArg $_ }))
|
|
$startInfo.UseShellExecute = $false; $startInfo.CreateNoWindow = $true; $startInfo.RedirectStandardOutput = $true; $startInfo.RedirectStandardError = $true
|
|
$process = [Diagnostics.Process]::new(); $process.StartInfo = $startInfo
|
|
$stopwatch = [Diagnostics.Stopwatch]::StartNew()
|
|
if (-not $process.Start()) { Fail 'failed to start native rg.exe' 2 }
|
|
$stdoutTask = $process.StandardOutput.ReadToEndAsync(); $stderrTask = $process.StandardError.ReadToEndAsync()
|
|
$timedOut = -not $process.WaitForExit($timeoutMs)
|
|
if ($timedOut) { try { $process.Kill() } catch {}; $process.WaitForExit() }
|
|
$stdoutText = $stdoutTask.Result; $stderrText = $stderrTask.Result; $stopwatch.Stop()
|
|
$lines = Text-Lines $stdoutText; $outputLimit = if ($filesOnly) { $maxFiles } else { $maxCount }; $selected = [string[]]($lines | Select-Object -First $outputLimit)
|
|
Print-Lines $selected
|
|
if (-not [string]::IsNullOrWhiteSpace($stderrText)) { [Console]::Error.Write($stderrText) }
|
|
$truncated = $lines.Count -gt $selected.Count
|
|
$matchedFiles = [Collections.Generic.HashSet[string]]::new([StringComparer]::OrdinalIgnoreCase)
|
|
if (-not $filesOnly) { foreach ($line in $selected) { if ($line -match '^(.+?):\d+:') { [void]$matchedFiles.Add($Matches[1]) } } }
|
|
$fileCount = if ($filesOnly) { $selected.Count } else { $matchedFiles.Count }
|
|
$encodingState = if ($stdoutText.Contains([char]0xfffd)) { 'legacy-or-invalid-utf8' } else { 'utf8-or-ascii' }
|
|
[Console]::Error.WriteLine('UNIDESK_WINDOWS_RG_SUMMARY matched=' + $selected.Count + ' fileCount=' + $fileCount + ' elapsedMs=' + $stopwatch.ElapsedMilliseconds + ' timeout=' + $timedOut.ToString().ToLowerInvariant() + ' encoding=' + $encodingState + ' skipped=0 fileLimit=' + ($filesOnly -and $truncated).ToString().ToLowerInvariant() + ' matchLimit=' + ((-not $filesOnly) -and $truncated).ToString().ToLowerInvariant() + ' engine=native-rg config=config/unidesk-cli.yaml#trans.windowsFs.rg')
|
|
if ($timedOut) { [Console]::Error.WriteLine('UNIDESK_WINDOWS_RG_HINT code=timeout exitCode=124 action=narrow-scope-or-add-glob message=retry-with-a-narrower-path-or-g/--glob'); exit 124 }
|
|
if ($process.ExitCode -ne 0) { exit $process.ExitCode }
|
|
exit 0
|
|
}
|