scripts/check-inline-lua-quotes

#!/usr/bin/env bash

check-inline-lua-quotes

Verify that no stray double quote appears inside a shell script's inline Lua

chunks, because one there silently corrupts the program it is embedded in.

#

General description (for a CEO): parts of this pipeline hand a snippet of one

programming language to another by wrapping it in quotation marks. Put a

quotation mark inside the snippet and the wrapper ends early -- the rest of the

snippet stops being a program and becomes a list of loose words, which the

receiving program then mistakes for instructions. Nothing reports an error; it

simply does the wrong thing. This tool reads the scripts and reports any

snippet whose quotation marks do not balance, so the mistake is caught by

running one command instead of by a stage failing an hour into a build.

#

The failure that prompted it (Issue 10-065): a comment inside one such chunk

read -- to be guarded by "if INFERENCE_SERVER is not empty", and an. The

shell ended the chunk at the first quote and passed `if INFERENCE_SERVER is not

empty...` to luajit as arguments. A module that infers the project root from

its first argument then took the word "is" as the root, and the stage died on

"Failed to load config from is/config.lua". bash -n sees nothing wrong,

because the script IS still valid shell -- it just means something else now.

#

Usage:

scripts/check-inline-lua-quotes [FILE]... # defaults to the known callers

Exit status: 0 when every chunk balances, 1 when any does not.

set -u

{{{ DIR resolution

Hard-coded project root with first-argument override is the project convention,

but this tool takes FILES as arguments, so the root is resolved from the script

location instead and any arguments are treated as files to check.

DIR="/mnt/mtwo/programming/ai-stuff/neocities-modernization"

}}}

{{{ default file list

The scripts known to embed Lua. A file with no inline chunks passes trivially,

so over-listing is harmless and under-listing is the real risk.

if [ "$#" -gt 0 ]; then
FILES=("$@")
else
FILES=(
"${DIR}/run.sh"
"${DIR}/generate-embeddings.sh"
"${DIR}/scripts/update"
"${DIR}/scripts/start-llamacpp-server.sh"
)
fi

}}}

{{{ check_file()

Walk a file, and for every line that opens an inline chunk, count double quotes

until the line that closes it. A correct chunk has exactly two: the opener and

the closer. Any other count means a quote inside the Lua source.

#

The opening pattern is assembled from pieces rather than written out, so this

checker does not flag its own source when pointed at itself.

check_file() {
local file="$1"
if [ ! -f "$file" ]; then
echo "check-inline-lua-quotes: no such file: $file" >&2
return 1
fi
awk -v fname="$file" '
BEGIN { open_pat = "luajit -e " "\""; bad = 0 }
index($0, open_pat) > 0 && !inblock {
# Only a chunk that CONTINUES past this line is worth tracking. An
# odd count of unescaped quotes means the string is still open at
# end of line; an even count means it opened and closed here, as in
# luajit -e "$LUA_EMBED_PROGRAM", where the Lua lives in a shell
# variable and this tool has nothing to say about it.
openline = $0
gsub(/\\"/, "", openline)
if (gsub(/"/, "\"", openline) % 2 == 1) {
inblock = 1; start = FNR; q = 1
}
next
}
inblock {
# The CLOSING line is checked first, and contributes exactly one
# quote -- the closer. Everything after that quote is ordinary shell
# (redirections, a || fallback, another quoted string) and has
# nothing to do with the Lua chunk. Counting the whole closing line
# was the first bug in this very tool: it reported two working blocks
# in generate-embeddings.sh as broken, because their closing line
# carries a redirection and a fallback string after the closer.
#
# Note for editors: this awk program is itself wrapped in SINGLE
# quotes, so an apostrophe in these comments would end it early --
# the same mistake, one language further down. Avoid apostrophes here.
if ($0 ~ /^[[:space:]]*"/) {
q += 1
if (q != 2) {
printf "%s:%d: inline Lua chunk has %d double quotes, expected 2\n", fname, start, q
bad = 1
}
inblock = 0
next
}
# Count only UNESCAPED quotes. A backslash-quote inside the chunk is
# correct and common: it puts a literal quote into the Lua source
# without ending the shell string, which is exactly how a Lua error
# message quotes a model name. Strip those from a copy of the line
# before counting, so the tool flags the dangerous form and stays
# quiet about the safe one.
line = $0
gsub(/\\"/, "", line)
q += gsub(/"/, "\"", line)
}
END {
if (inblock) {
printf "%s:%d: inline Lua chunk never closes\n", fname, start
bad = 1
}
exit bad
}
' "$file"
}

}}}

status=0
for f in "${FILES[@]}"; do
check_file "$f" || status=1
done

if [ "$status" -eq 0 ]; then
echo "check-inline-lua-quotes: all inline Lua chunks balance"
fi
exit "$status"