fix(portability): one python/python3 note + cross-shell guidance for bash-only labs
- M1: single prominent note that the command may be python3/pip3 (modern macOS,
default Debian/Ubuntu); referenced rather than repeated.
- Cross-shell notes where bash-only commands appear: M1 mkdir -p, M12 rm -f,
M16 bind-mount (braced ${PWD} + PowerShell note), M19 inspect-runner.sh gains a
timeout/gtimeout/bash-native fallback so it doesn't hang on stock macOS.
Closes #31
Closes #32
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TfzV5QvtPDz8LJS3Pu5VLT
This commit is contained in:
@@ -137,6 +137,12 @@ purpose** so you recognize it later.
|
||||
- Python 3.10 or newer (`python --version` or `python3 --version` to check).
|
||||
- Your usual AI chat assistant, open in a browser tab.
|
||||
|
||||
> **One command name, the whole course through:** whichever of `python` / `python3` just printed a
|
||||
> 3.10+ version is the command to use in *every* lab from here on. The labs are written with
|
||||
> `python`; if that's "command not found" on your machine — common on current macOS and default
|
||||
> Debian/Ubuntu, where Python is installed only as `python3` — read it as `python3` (and `pip3`
|
||||
> wherever a lab uses `pip`). This note holds course-wide; we won't repeat it.
|
||||
|
||||
### Get the course materials
|
||||
|
||||
Everything you'll run in this course lives in one repo. Grab it once, up front — no tools required
|
||||
@@ -170,6 +176,10 @@ You now have every module's files locally, including this one's under
|
||||
|
||||
(Copy them however you like — drag-and-drop in your editor's file explorer is fine.)
|
||||
|
||||
> **On Windows:** these labs' shell snippets are written for bash — run them from **Git Bash** or
|
||||
> **WSL** and they work as-is. In native PowerShell a few POSIX-only commands differ; here, `mkdir
|
||||
> -p` becomes `New-Item -ItemType Directory -Force`.
|
||||
|
||||
2. Open the folder in your editor (`code .` if you're using VS Code, or File → Open Folder).
|
||||
|
||||
3. Run it in your terminal to confirm it works:
|
||||
|
||||
@@ -305,6 +305,10 @@ do them once on purpose now.
|
||||
git log --oneline # the bad merge is STILL there, with a revert after it
|
||||
```
|
||||
|
||||
> **On Windows:** `rm -f` is bash. Run this lab from Git Bash or WSL (it works as-is), or use
|
||||
> PowerShell's `Remove-Item -Force tasks.json`. Every other command here is Git, identical across
|
||||
> shells.
|
||||
|
||||
That last point is the whole lesson: you undid the effect **without rewriting history**. Anyone who
|
||||
pulled the bad merge just pulls your revert on top and they're fine.
|
||||
|
||||
|
||||
@@ -226,10 +226,14 @@ containerize and run the app you already have.
|
||||
image (that keeps it lean; see *Where it breaks*):
|
||||
|
||||
```bash
|
||||
docker run --rm -v "$PWD":/app -w /app python:3.12-slim \
|
||||
docker run --rm -v "${PWD}:/app" -w /app python:3.12-slim \
|
||||
python -m unittest
|
||||
```
|
||||
|
||||
> **On Windows:** this step bind-mounts your code, so the host path matters. Run it from WSL (or
|
||||
> Git Bash), or from PowerShell — `${PWD}` resolves correctly in each. The other `docker run`
|
||||
> commands mount nothing of yours and are identical everywhere.
|
||||
|
||||
This is, in miniature, exactly what containerized CI does. If it passes here, it passes the same
|
||||
way on any machine with the engine — your laptop's local Python version is now irrelevant.
|
||||
|
||||
|
||||
@@ -15,6 +15,26 @@ set -u
|
||||
|
||||
line() { printf '\n=== %s ===\n' "$1"; }
|
||||
|
||||
# Try a TCP connect to host:port with a ~2s deadline, portably.
|
||||
# GNU `timeout` (Linux) or Homebrew's `gtimeout` are used when present; otherwise a bash-native
|
||||
# background-and-kill fallback keeps this working on stock macOS, which ships no GNU `timeout`.
|
||||
tcp_probe() {
|
||||
host="$1"; port="$2"
|
||||
if command -v timeout >/dev/null 2>&1; then
|
||||
timeout 2 bash -c ">/dev/tcp/${host}/${port}" 2>/dev/null
|
||||
elif command -v gtimeout >/dev/null 2>&1; then
|
||||
gtimeout 2 bash -c ">/dev/tcp/${host}/${port}" 2>/dev/null
|
||||
else
|
||||
bash -c ">/dev/tcp/${host}/${port}" 2>/dev/null &
|
||||
probe_pid=$!
|
||||
( sleep 2; kill "$probe_pid" 2>/dev/null ) >/dev/null 2>&1 &
|
||||
killer_pid=$!
|
||||
rc=0; wait "$probe_pid" 2>/dev/null || rc=$?
|
||||
kill "$killer_pid" 2>/dev/null
|
||||
return "$rc"
|
||||
fi
|
||||
}
|
||||
|
||||
line "WHO AND WHERE"
|
||||
echo "hostname : $(hostname 2>/dev/null)"
|
||||
echo "user : $(whoami 2>/dev/null) (root? $( [ "$(id -u 2>/dev/null)" = 0 ] && echo YES || echo no ))"
|
||||
@@ -62,7 +82,7 @@ line "PRIVATE NETWORK REACH (the reason you self-host — and the reason it's da
|
||||
PROBES=( "192.168.0.1:80" "192.168.1.1:80" "10.0.0.1:80" )
|
||||
for hp in "${PROBES[@]}"; do
|
||||
host="${hp%%:*}"; port="${hp##*:}"
|
||||
if timeout 2 bash -c ">/dev/tcp/${host}/${port}" 2>/dev/null; then
|
||||
if tcp_probe "$host" "$port"; then
|
||||
echo " REACHABLE: ${host}:${port}"
|
||||
fi
|
||||
done
|
||||
|
||||
Reference in New Issue
Block a user