Skip to content

Commit b558288

Browse files
fix(scripts): improve accessible command output
- add non-mutating configuration previews - honor no-color output for Viewer startup - keep redirected progress readable and rate limited ♿ - Generated by Copilot
1 parent 8f090b9 commit b558288

3 files changed

Lines changed: 125 additions & 0 deletions

File tree

scripts/tests/setup-dev.Tests.ps1

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -253,3 +253,83 @@ Describe 'setup-dev uv bootstrap' -Tag 'Unit' {
253253
} | Should -Throw 'Failed to install uv v0.11.21'
254254
}
255255
}
256+
257+
$script:GitBashPath = Join-Path $env:ProgramFiles 'Git/bin/bash.exe'
258+
$script:BashAvailable = (Test-Path -LiteralPath $script:GitBashPath) -or
259+
$null -ne (Get-Command bash -ErrorAction SilentlyContinue)
260+
261+
Describe 'Bash launcher accessibility contracts' -Tag 'Unit' {
262+
BeforeAll {
263+
$script:RepositoryRoot = Resolve-Path (Join-Path $PSScriptRoot '../..')
264+
$gitBash = if ($env:ProgramFiles) {
265+
Join-Path $env:ProgramFiles 'Git/bin/bash.exe'
266+
}
267+
else {
268+
$null
269+
}
270+
$script:BashExecutable = if ($gitBash -and (Test-Path -LiteralPath $gitBash)) {
271+
$gitBash
272+
}
273+
else {
274+
'bash'
275+
}
276+
function ConvertTo-BashPath {
277+
param([string]$Path)
278+
279+
$normalized = $Path.Replace('\', '/')
280+
if ($script:BashExecutable -ne 'bash') {
281+
return $normalized
282+
}
283+
if ($normalized -match '^([A-Za-z]):/(.*)$') {
284+
return "/mnt/$($Matches[1].ToLowerInvariant())/$($Matches[2])"
285+
}
286+
return $normalized
287+
}
288+
289+
$script:SetupDevBashPath = ConvertTo-BashPath (Join-Path $script:RepositoryRoot 'setup-dev.sh')
290+
$script:ViewerStartPath = ConvertTo-BashPath (
291+
Join-Path $script:RepositoryRoot 'data-management/viewer/start.sh'
292+
)
293+
}
294+
295+
It 'Provides setup help without requiring deployment tools' -Skip:(-not $script:BashAvailable) {
296+
$output = & $script:BashExecutable $script:SetupDevBashPath --help 2>&1
297+
298+
$LASTEXITCODE | Should -Be 0
299+
$output -join "`n" | Should -Match 'Usage:'
300+
$output -join "`n" | Should -Match '--config-preview'
301+
}
302+
303+
It 'Previews setup configuration without mutation' -Skip:(-not $script:BashAvailable) {
304+
$output = & $script:BashExecutable $script:SetupDevBashPath --config-preview 2>&1
305+
306+
$LASTEXITCODE | Should -Be 0
307+
$output -join "`n" | Should -Match 'Configuration Preview'
308+
$output -join "`n" | Should -Match 'Mutation.*None'
309+
}
310+
311+
It 'Previews Viewer configuration without ANSI output when NO_COLOR is present' -Skip:(-not $script:BashAvailable) {
312+
$originalNoColor = $env:NO_COLOR
313+
try {
314+
$env:NO_COLOR = '1'
315+
$output = & $script:BashExecutable $script:ViewerStartPath --config-preview 2>&1
316+
}
317+
finally {
318+
$env:NO_COLOR = $originalNoColor
319+
}
320+
321+
$LASTEXITCODE | Should -Be 0
322+
$text = $output -join "`n"
323+
$text | Should -Match 'Configuration Preview'
324+
$text | Should -Match 'Mutation.*None'
325+
$text | Should -Not -Match ([regex]::Escape([char]27))
326+
}
327+
328+
It 'Rejects an unknown Viewer option with visible recovery guidance' -Skip:(-not $script:BashAvailable) {
329+
$output = & $script:BashExecutable $script:ViewerStartPath --not-a-real-option 2>&1
330+
331+
$LASTEXITCODE | Should -Not -Be 0
332+
$output -join "`n" | Should -Match 'Unknown option.*--not-a-real-option'
333+
$output -join "`n" | Should -Match 'Usage:'
334+
}
335+
}

setup-dev.sh

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,15 +4,38 @@ set -euo pipefail
44
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
55
VENV_DIR="${SCRIPT_DIR}/.venv"
66
DISABLE_VENV=false
7+
CONFIG_PREVIEW=false
8+
9+
show_help() {
10+
cat << EOF
11+
Usage: $(basename "$0") [OPTIONS]
12+
13+
Prepare the local Physical AI Toolchain development environment.
14+
15+
Options:
16+
--disable-venv Install packages without creating .venv
17+
--config-preview Print local configuration and exit without changes
18+
--help, -h Show this help message
19+
EOF
20+
}
721

822
while [[ $# -gt 0 ]]; do
923
case $1 in
1024
--disable-venv)
1125
DISABLE_VENV=true
1226
shift
1327
;;
28+
--config-preview)
29+
CONFIG_PREVIEW=true
30+
shift
31+
;;
32+
--help|-h)
33+
show_help
34+
exit 0
35+
;;
1436
*)
1537
echo "Unknown option: $1" >&2
38+
show_help >&2
1639
exit 1
1740
;;
1841
esac
@@ -21,6 +44,15 @@ done
2144
# shellcheck source=scripts/lib/common.sh
2245
source "${SCRIPT_DIR}/scripts/lib/common.sh"
2346

47+
if [[ "${CONFIG_PREVIEW}" == "true" ]]; then
48+
section "Configuration Preview"
49+
print_kv "Repository" "${SCRIPT_DIR}"
50+
print_kv "Python" "$(cat "${SCRIPT_DIR}/.python-version")"
51+
print_kv "Virtual Environment" "$([[ "${DISABLE_VENV}" == "true" ]] && echo disabled || echo "${VENV_DIR}")"
52+
print_kv "Mutation" "None"
53+
exit 0
54+
fi
55+
2456
# Preamble: Recommend devcontainer for easier setup
2557
echo
2658
echo "💡 RECOMMENDED: Use the Dev Container for the best experience."

training/tests/test_stream_hypothesis.py

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -163,6 +163,19 @@ def test_install_ansi_stripping_preserves_existing_tqdm_interval(monkeypatch) ->
163163
assert stream_module.os.environ["TQDM_MININTERVAL"] == "5"
164164

165165

166+
def test_redirected_progress_is_line_oriented_and_rate_limited(monkeypatch) -> None:
167+
"""Redirected progress remains readable without flooding log consumers."""
168+
stdout = CaptureStream()
169+
monkeypatch.setattr(stream_module.sys, "stdout", stdout)
170+
monkeypatch.delenv("TQDM_MININTERVAL", raising=False)
171+
172+
stream_module.install_ansi_stripping()
173+
stream_module.sys.stdout.write("\x1b[32m" "step 1\x1b[0m\rstep 2\r")
174+
175+
assert stdout.value == "step 1\nstep 2\n"
176+
assert stream_module.os.environ["TQDM_MININTERVAL"] == "30"
177+
178+
166179
def test_install_ansi_stripping_does_not_double_wrap_stdout(monkeypatch) -> None:
167180
"""install_ansi_stripping keeps an existing AnsiStrippingStream instance."""
168181
existing = AnsiStrippingStream(CaptureStream())

0 commit comments

Comments
 (0)