Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion .github/workflows/unit-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ jobs:

- name: Install test deps
run: |
sudo apt-get install -y bats
sudo apt-get install -y bats fish zsh
pip install pytest pytest-cov pyyaml

- name: Run shellcheck — extensionless scripts
Expand Down Expand Up @@ -81,6 +81,9 @@ jobs:
- name: Run bats (ublue-bling)
run: bats tests/test_bling.bats

- name: Run bats (ujust completion)
run: bats tests/test_ujust_completion.bats

- name: Run bats (bling.sh)
run: bats tests/test_bling_sh.bats

Expand Down
25 changes: 20 additions & 5 deletions Containerfile
Original file line number Diff line number Diff line change
Expand Up @@ -23,11 +23,6 @@ RUN mkdir -p /out/bluefin/usr/share/backgrounds/bluefin && \
mv /out/bluefin/usr/share/*.jxl /out/bluefin/usr/share/*.xml /out/bluefin/usr/share/backgrounds/bluefin && \
sed -i 's|~\/\.local\/share|\/usr\/share|' /out/bluefin/usr/share/backgrounds/bluefin/*.xml /out/bluefin/usr/share/gnome-background-properties/*.xml

RUN install -d /out/shared/usr/share/bash-completion/completions /out/shared/usr/share/zsh/site-functions /out/shared/usr/share/fish/vendor_completions.d/ && \
just --completions bash | sed -E 's/([\(_" ])just/\1ujust/g' > /out/shared/usr/share/bash-completion/completions/ujust && \
just --completions zsh | sed -E 's/([\(_" ])just/\1ujust/g' > /out/shared/usr/share/zsh/site-functions/_ujust && \
just --completions fish | sed -E 's/([\(_" ])just/\1ujust/g' > /out/shared/usr/share/fish/vendor_completions.d/ujust.fish

# Fetch game-devices-udev rules as individual raw files at a fixed commit SHA.
# Codeberg/Gitea archive tarballs are generated on demand and their checksums
# drift across infra changes, so per-file raw fetches with sha256 pins are used
Expand Down Expand Up @@ -83,6 +78,26 @@ RUN set -e && mkdir -p /out/bluefin/etc/bazaar && \
COPY --from=umotd-build /umotd /out/shared/usr/bin/umotd
COPY --from=uwelcome-build /uwelcome /out/shared/usr/bin/uwelcome

# Ujust gate: the tailored completions checked into system_files/shared must bind `ujust`
# & /out/shared must not ship files at the same paths to avoid shadow by ctx overlay.
COPY system_files/shared/usr/share/bash-completion/completions/ujust \
system_files/shared/usr/share/zsh/site-functions/_ujust \
system_files/shared/usr/share/fish/vendor_completions.d/ujust.fish \
system_files/shared/usr/share/ublue-os/just/ujust-flags \
/tmp/ujust-gate/
RUN set -e; \
grep -qE '^complete -F _ujust ujust$' /tmp/ujust-gate/ujust; \
grep -qE '^#compdef ujust$' /tmp/ujust-gate/_ujust; \
grep -qE '^complete -c ujust ' /tmp/ujust-gate/ujust.fish; \
grep -qE '^[[:space:]]*local flags_file=.*ujust-flags' /tmp/ujust-gate/ujust; \
grep -qE '^[[:space:]]*local flags_file=.*ujust-flags' /tmp/ujust-gate/_ujust; \
grep -qE '^[[:space:]]*echo .*ujust-flags' /tmp/ujust-gate/ujust.fish; \
grep -qx -- '--version' /tmp/ujust-gate/ujust-flags; \
if grep -qF 'JUST_COMPLETE' /tmp/ujust-gate/ujust /tmp/ujust-gate/_ujust /tmp/ujust-gate/ujust.fish; then echo "ujust completion is a just dynamic-loader shim" >&2; exit 1; fi; \
for f in usr/share/bash-completion/completions/ujust usr/share/zsh/site-functions/_ujust usr/share/fish/vendor_completions.d/ujust.fish usr/share/ublue-os/just/ujust-flags; do \
if [ -e "/out/shared/${f}" ]; then echo "ujust completion shadowed by /out/shared/${f}" >&2; exit 1; fi; \
done

FROM scratch AS ctx
COPY /system_files/shared /system_files/shared/
COPY /bluefin-branding/system_files /system_files/bluefin
Expand Down
1 change: 1 addition & 0 deletions Justfile
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ test:
bats tests/test_update_just.bats
bats tests/test_native_recipes.bats
bats tests/test_ujust.bats
bats tests/test_ujust_completion.bats
bats tests/test_ublue_fastfetch.bats
bats tests/test_motd_integration.bats
bats tests/test_clean_system_podman_path.bats
Expand Down
6 changes: 3 additions & 3 deletions docs/skills/containerfile/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ The Containerfile uses four named stages:
| `build` | Downloads and assembles all artifacts into `/out/` |
| `ctx` | Scratch image: the OCI layer consumed by downstream builds |

See [`references/build-stages.md`](references/build-stages.md) for the full stage details, wallpaper source caveat, and ujust completion generation.
See [`references/build-stages.md`](references/build-stages.md) for the full stage details, wallpaper source caveat, and ujust completions.

## Key Rules

Expand All @@ -57,7 +57,7 @@ See [`references/build-stages.md`](references/build-stages.md) for the full stag

- `checkout tags/...` or `--branch` in a Go builder stage — tags are mutable.
- A `curl` block without an inline `sha256sum -c`.
- Editing generated ujust completions directly instead of fixing the `sed` pattern.
- Reintroducing a `just --completions | sed` generator for ujust completions, or shipping files at the ujust completion paths from `/out/shared/`, instead of editing the checked-in files under `system_files/shared/` — the `build` stage `RUN` gate fails the build.
- Using `ghcr.io/projectbluefin/` for the wallpaper source (it is `ublue-os`).

## Verification
Expand All @@ -71,5 +71,5 @@ See [`references/build-stages.md`](references/build-stages.md) for the full stag

| File | Description |
|---|---|
| [`references/build-stages.md`](references/build-stages.md) | Full build stage definitions, wallpaper source caveat, and ujust completion generation details. |
| [`references/build-stages.md`](references/build-stages.md) | Full build stage definitions, wallpaper source caveat, and ujust completion details. |
| [`references/binary-and-testing.md`](references/binary-and-testing.md) | External binary SHA verification pattern, local testing with `just overlay`, adding a new binary, and Renovate tracking. |
16 changes: 7 additions & 9 deletions docs/skills/containerfile/references/build-stages.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Containerfile — Build Stages

Part of [containerfile](../SKILL.md) — full stage definitions, wallpaper source caveat, and ujust completion generation.
Part of [containerfile](../SKILL.md) — full stage definitions, wallpaper source caveat, and ujust completions.

## Build stages

Expand Down Expand Up @@ -100,14 +100,12 @@ sed -i 's|~\/\.local\/share|\/usr\/share|' *.xml

---

## ujust completion generation
## ujust completions

The `ujust` shell completions are **not hand-authored** — they are generated at build time from the `just` binary by replacing all occurrences of `just` with `ujust` in the completion output:
The `ujust` shell completions are tailored files checked into `system_files/shared/` (bash, zsh, fish), completing `ujust` flags plus recipe names from `/usr/share/ublue-os/just/00-entry.just` via `just --summary`.
They are **not** generated from `just --completions`: Since `just` moved to dynamic `clap_complete` loader output, a build-time `sed s/just/ujust/` rename can no longer work. The real registration line (`complete ... just`) is emitted at TAB-time on the live system, past any build-time filter, and binds the wrong command name (projectbluefin/bluefin#1171).

```bash
just --completions bash | sed -E 's/([\(_" ])just/\1ujust/g' > .../completions/ujust
just --completions zsh | sed -E 's/([\(_" ])just/\1ujust/g' > .../_ujust
just --completions fish | sed -E 's/([\(_" ])just/\1ujust/g' > .../ujust.fish
```
Two rules follow from this:

The sed pattern `([\(_" ])just` only substitutes `just` when preceded by `(`, `_`, `"`, ` `, or `(` — avoiding substring matches inside longer words. Do not edit the generated completions directly; edit the sed pattern if the substitution is wrong.
- Never reintroduce a `just --completions | sed` generator step. The gate `RUN` in the `build` stage validates uncommented completion registrations and `ujust-flags` path assignments in the checked-in files, plus a no-shadow check against `/out/shared/...`. It fails if the generator — or any other file at those paths — comes back.
- `UJUST_JUSTFILE` / `UJUST_FLAGS_FILE` override the entry-justfile path and the flags list in all three completions; they exist for `tests/test_ujust_completion.bats` which points them at sandbox files so the suite passes off-image. Flags live in exactly one place at `system_files/shared/usr/share/ublue-os/just/ujust-flags` (one per line). All three completions read it during TAB press.
41 changes: 41 additions & 0 deletions system_files/shared/usr/share/bash-completion/completions/ujust
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
# bash completion for ujust
#
# Flags come from the ujust-flags data file shipped next to the entry
# justfile (one flag per line). When `just --help` gains flags, update the
# data file — the completions read it at TAB time, no per-shell edits needed.

_ujust() {
local cur words cword
if declare -F _init_completion >/dev/null 2>&1; then
_init_completion || return
else
COMPREPLY=()
cur="${COMP_WORDS[COMP_CWORD]}"
words=("${COMP_WORDS[@]}")
cword="${COMP_CWORD}"
fi

# UJUST_JUSTFILE / UJUST_FLAGS_FILE overrides exist for testing;
# defaults are the image entry justfile and the flags list next to it.
local justfile="${UJUST_JUSTFILE:-/usr/share/ublue-os/just/00-entry.just}"
local flags_file="${UJUST_FLAGS_FILE:-${justfile%/*}/ujust-flags}"

if [[ "${cur}" == -* ]]; then
local flags=()
if [[ -f "${flags_file}" ]]; then
mapfile -t flags < "${flags_file}"
fi
COMPREPLY=( $(compgen -W "${flags[*]}" -- "${cur}") )
return 0
fi

# Recipe completion: if just is installed and entry justfile exists, fetch recipe list
if [[ -f "${justfile}" ]] && command -v just >/dev/null 2>&1; then
local recipes
recipes=$(just --summary --justfile "${justfile}" 2>/dev/null)
COMPREPLY=( $(compgen -W "${recipes}" -- "${cur}") )
return 0
fi
}

complete -F _ujust ujust
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
# fish completion for ujust
#
# Flags come from the ujust-flags data file shipped next to the entry
# justfile (one flag per line). When `just --help` gains flags, update the
# data file — the completions read it at TAB time, no per-shell edits needed.

function __ujust_justfile
# UJUST_JUSTFILE override exists for testing; default is the image entry justfile.
if set -q UJUST_JUSTFILE
echo $UJUST_JUSTFILE
else
echo /usr/share/ublue-os/just/00-entry.just
end
end

function __ujust_flags_file
# UJUST_FLAGS_FILE override exists for testing; default sits next to the entry justfile.
if set -q UJUST_FLAGS_FILE
echo $UJUST_FLAGS_FILE
else
echo (string replace -r '/[^/]*$' '' (__ujust_justfile))/ujust-flags
end
end

function __ujust_recipes
just --summary --justfile (__ujust_justfile) 2>/dev/null | tr ' ' '\n'
end

function __ujust_flags
if test -f (__ujust_flags_file)
cat (__ujust_flags_file)
end
end

complete -c ujust -f -a '(__ujust_recipes)'
complete -c ujust -f -a '(__ujust_flags)'
83 changes: 83 additions & 0 deletions system_files/shared/usr/share/ublue-os/just/ujust-flags
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
--alias-style
--allow-missing
--ceiling
--changelog
--check
--choose
--chooser
--clean
--clear-shell-args
--color
--command
--command-color
--complete-aliases
--completions
--cygpath
--default-list
--dotenv-command
--dotenv-filename
--dotenv-path
--dry-run
--dump
--dump-format
--edit
--evaluate
--evaluate-format
--explain
--fmt
--global-justfile
--group
--groups
--help
--highlight
--indentation
--init
--jobs
--json
--justfile
--justfile-name
--list
--list-heading
--list-prefix
--list-submodules
--man
--no-aliases
--no-cache
--no-deps
--no-dotenv
--no-highlight
--one
--quiet
--set
--shell
--shell-arg
--shell-command
--show
--summary
--tempdir
--time
--timestamp
--timestamp-format
--unsorted
--unstable
--usage
--variables
--verbose
--version
--working-directory
--yes
-c
-d
-e
-E
-f
-F
-g
-h
-l
-n
-q
-s
-u
-v
-V
39 changes: 39 additions & 0 deletions system_files/shared/usr/share/zsh/site-functions/_ujust
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
#compdef ujust

_ujust() {
# UJUST_JUSTFILE override exists for testing; default is the image entry justfile.
local justfile="${UJUST_JUSTFILE:-/usr/share/ublue-os/just/00-entry.just}"

if (( CURRENT == 2 )); then
# Complete flags from the ujust-flags data file shipped next to
# the entry justfile (one flag per line). Falls through to recipes
# if the data file is missing.
if [[ "${words[CURRENT]}" == -* ]]; then
local flags_file="${UJUST_FLAGS_FILE:-${justfile:h}/ujust-flags}"
if [[ -f "$flags_file" ]]; then
local -a flags
flags=(${(f)"$(<$flags_file)"})
_describe -t flags 'flag' flags && return 0
fi
fi

if [[ -f "$justfile" ]] && (( $+commands[just] )); then
local -a recipes
recipes=(${(f)"$(_call_program recipes just --summary --justfile "$justfile" 2>/dev/null)"})
# just --summary outputs recipe names separated by spaces
recipes=($=recipes)
if (( $#recipes > 0 )); then
_describe -t recipes 'recipe' recipes && return 0
fi
fi
fi

# Fall back to native just completion if available
if (( $+functions[_just] )); then
words=(just --justfile "$justfile" "${words[@]:1}")
(( CURRENT += 2 ))
_just
fi
}

_ujust "$@"
Loading
Loading