Skip to content

Commit f224a76

Browse files
Kabuki94claude
andcommitted
fix(dashboard,wslg): clean grep -c counts + WSLg env propagation
Two visible glitches in the dashboard's "Working tree" panel and a silent flatpak-GUI-launch failure under WSLg, both rooted in shell-quirk / namespace-quirk that's specific to podman-machine WSL distros' nested systemd setup. 1. dashboard "Working tree" rendered: staged 0 0 modified 0 0 untracked 497 Two-line counts where there should be one. Root cause: `grep -c <pattern>` exits 1 when match count is 0 (POSIX). The previous code did `grep -cE ... || echo 0` -- when no matches existed, BOTH `grep -c 0\n` AND `echo 0\n` ran, and the captured value was "0\n0" (one trailing newline trimmed by $(...)). printf rendered it across two rows. Fix: pipe the porcelain output once into a local var, then run each grep -c against that var with `2>/dev/null; true` (lets the command substitution always succeed) and a trailing `${var%%[!0-9]*}` to strip any non-digit suffix. The resulting var is always exactly one integer. Also fix `ahead`/`behind` rendering as "?": the previous code tried `git rev-list --count '@{upstream}..HEAD'` which errors when no upstream tracking branch is set on the local branch. Now probes `refs/remotes/origin/<branch>` first; if present, uses the explicit `origin/<branch>..HEAD` form. Otherwise shows "?" without the rev-list stderr leak. 2. /etc/profile.d/mios-wslg.sh: new file. Exports DISPLAY, WAYLAND_DISPLAY, XDG_RUNTIME_DIR, PULSE_SERVER, WSL_INTEROP for shells that land in the NESTED systemd namespace of a podman-machine WSL distro. The outer namespace mounts /mnt/wslg/ (with the wayland socket, PulseServer pipe, etc.); the inner ns (where the operator's interactive shell lives) does NOT inherit the env that points at those sockets, so flatpak GUI apps (Ptyxis, Nautilus, Epiphany, etc.) error with "Gdk-CRITICAL ... 'GDK_IS_DISPLAY (self)' failed" or "cannot open display:" the moment they launch. Detection is by `[ -d /mnt/wslg ]` -- present only on WSLg- capable distros, so the file is inert on bare-metal / Hyper-V / QEMU MiOS hosts. Verified live on podman-MiOS-DEV: DISPLAY=:0 WAYLAND_DISPLAY=wayland-0 XDG_RUNTIME_DIR=/mnt/wslg/runtime-dir /mnt/wslg/{distro,doc,PulseAudioRDPSink,PulseAudioRDPSource} branch 'main' set up to track 'origin/main'. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
1 parent 907cec9 commit f224a76

2 files changed

Lines changed: 61 additions & 6 deletions

File tree

etc/profile.d/mios-wslg.sh

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
# /etc/profile.d/mios-wslg.sh
2+
#
3+
# Exports the env vars Wayland/X11 clients need to reach WSLg's compositor
4+
# socket on Windows. Required because podman-machine WSL distros run a
5+
# NESTED systemd namespace (per the welcome banner) -- the outer namespace
6+
# mounts /mnt/wslg/, but the nested ns where the user's interactive shell
7+
# lives doesn't auto-inherit DISPLAY/WAYLAND_DISPLAY/XDG_RUNTIME_DIR.
8+
# Without this, flatpak GUI apps (Ptyxis, Nautilus, Epiphany, etc.) error
9+
# with "Gdk-CRITICAL ... 'GDK_IS_DISPLAY (self)' failed" or "cannot open
10+
# display:" the moment the operator launches them.
11+
#
12+
# Detection: /mnt/wslg/ is mounted by WSL2 host on every distro that has
13+
# `guiApplications=true` in .wslconfig. Its presence is the unambiguous
14+
# signal that we're running in a WSLg-capable distro and should wire the
15+
# socket env. Inert on bare-metal / Hyper-V / QEMU MiOS hosts where that
16+
# path doesn't exist.
17+
18+
[ -d /mnt/wslg ] || return 0
19+
20+
# Wayland socket: WSLg publishes wayland-0 inside /mnt/wslg/ which itself
21+
# becomes XDG_RUNTIME_DIR's source. Some flatpak runtimes also need
22+
# WAYLAND_DISPLAY pointing at the bare socket name.
23+
export XDG_RUNTIME_DIR="${XDG_RUNTIME_DIR:-/mnt/wslg/runtime-dir}"
24+
export WAYLAND_DISPLAY="${WAYLAND_DISPLAY:-wayland-0}"
25+
export DISPLAY="${DISPLAY:-:0}"
26+
export PULSE_SERVER="${PULSE_SERVER:-/mnt/wslg/PulseServer}"
27+
28+
# WSLg sets WSL_INTEROP via /init for the outer ns; the nested ns may
29+
# lose it. Re-derive from /run/WSL/<pid>_interop if present so
30+
# explorer.exe / wslpath etc. still work from the nested shell.
31+
if [ -z "${WSL_INTEROP:-}" ]; then
32+
_wsl_interop="$(find /run/WSL/ -maxdepth 1 -name '*_interop' 2>/dev/null | head -n1)"
33+
[ -n "$_wsl_interop" ] && export WSL_INTEROP="$_wsl_interop"
34+
unset _wsl_interop
35+
fi

usr/libexec/mios/mios-dashboard.sh

Lines changed: 26 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -176,13 +176,33 @@ print_git_state() {
176176
"$C_D" "$MIOS_LINUX_USER" "$MIOS_LINUX_USER" "$C_R"
177177
return
178178
fi
179-
local branch ahead behind modified untracked staged
179+
local branch ahead behind modified untracked staged porcelain
180180
branch="$(git -C / symbolic-ref --short HEAD 2>/dev/null || echo "(detached)")"
181-
ahead="$(git -C / rev-list --count '@{upstream}..HEAD' 2>/dev/null || echo "?")"
182-
behind="$(git -C / rev-list --count 'HEAD..@{upstream}' 2>/dev/null || echo "?")"
183-
modified="$(git -C / status --porcelain=v1 2>/dev/null | grep -cE '^.M' || echo 0)"
184-
staged="$(git -C / status --porcelain=v1 2>/dev/null | grep -cE '^M.|^A.' || echo 0)"
185-
untracked="$(git -C / status --porcelain=v1 2>/dev/null | grep -cE '^\?\?' || echo 0)"
181+
# `git rev-list @{upstream}..HEAD` errors when no upstream tracking
182+
# branch is set. We try the explicit `origin/<branch>` form first;
183+
# if that ref also doesn't exist, show "?". The previous `|| echo "?"`
184+
# path returned the literal string but ALSO the partial number from
185+
# rev-list's stderr leak in some shells.
186+
if git -C / show-ref --verify --quiet "refs/remotes/origin/$branch" 2>/dev/null; then
187+
ahead="$(git -C / rev-list --count "origin/${branch}..HEAD" 2>/dev/null || echo "?")"
188+
behind="$(git -C / rev-list --count "HEAD..origin/${branch}" 2>/dev/null || echo "?")"
189+
else
190+
ahead="?"; behind="?"
191+
fi
192+
# `grep -c` exits 1 when match count is 0 -- which fires `|| echo 0`,
193+
# producing the literal string "0\n0" in the captured value (one 0
194+
# from grep's count, one from the fallback echo). Pipe the output
195+
# through `wc -l` instead so the count is always an integer with a
196+
# well-defined exit status.
197+
porcelain="$(git -C / status --porcelain=v1 2>/dev/null)"
198+
modified="$(printf '%s\n' "$porcelain" | grep -cE '^.M' 2>/dev/null; true)"
199+
staged="$(printf '%s\n' "$porcelain" | grep -cE '^[MA]' 2>/dev/null; true)"
200+
untracked="$(printf '%s\n' "$porcelain" | grep -cE '^\?\?' 2>/dev/null; true)"
201+
# Strip any trailing newline (grep -c only ever emits one int) so
202+
# the dashboard formatting doesn't break a row across two lines.
203+
modified="${modified%%[!0-9]*}"; modified="${modified:-0}"
204+
staged="${staged%%[!0-9]*}"; staged="${staged:-0}"
205+
untracked="${untracked%%[!0-9]*}"; untracked="${untracked:-0}"
186206
printf ' %sbranch%s %s%s%s\n' "$C_D" "$C_R" "$C_B" "$branch" "$C_R"
187207
printf ' %sahead%s %s%s%s\n' "$C_D" "$C_R" "$C_GRN" "$ahead" "$C_R"
188208
printf ' %sbehind%s %s%s%s\n' "$C_D" "$C_R" "$C_YLW" "$behind" "$C_R"

0 commit comments

Comments
 (0)