voronstl/web/batch_glb_png/link_glbs.sh

114 lines
3.9 KiB
Bash
Executable file

#!/bin/sh
# 20260228 ChatGPT
# $Header$
#
# This script creates links from the staging directory to
# the glbs sibling directory. The staging directory is where the glbs are staged for rendering.
# The glbs sibling directory is where the PNG & webP batch renderer expects to find the glbs. The files names
# are sanitized to be filesystem safe and to avoid collisions by adding the path components
# delimited by double underscores.
# If a collision is detected, a numeric suffix is added to disambiguate.
# Consequently, the name of the link is not the same as the original glb, but contains the original path
# components in a sanitized form. This allows the batch renderer to process all the glbs without worrying
# about name collisions, while still retaining some traceability to the original files.
#
# For example, if the staging directory contains:
# /home/jlpoole/work/Voron/test1/Klicky-Probe/Printers/Voron/v1.8_v2.4_Legacy_Trident/v1.8_v2.4_Legacy_Trident_STL/Dock_mount_fixed_v2.glb
# then this script will create the very long file name:
# glbs/Klicky-Probe__Printers__Voron__...__Dock_mount_fixed_v2.stl.glb
#
# Note: the brackets in a file name, e.g. "[a]" are preserved.
# Another example, if the staging directory contains:
# /home/jlpoole/work/Voron/test1/Voron/Skirts/[a]_belt_guard_a_x2.stl.glb
# then this script will create the file name:
# 'Voron-2__STLs__Skirts__[a]_belt_guard_a_x2.stl.glb'
#
# Copy/paste:
# cd ~/work/Voron/renderlab/web/batch_glb_png
# chmod +x link_glbs.sh
# ./link_glbs.sh /home/jlpoole/work/Voron/test1
#
# This creates symlinks under ./glbs/ pointing to every *.glb under the staging directory.
set -eu
ROOT="${1:-}"
[ -n "$ROOT" ] || { echo "Usage: $0 /path/to/root" >&2; exit 2; }
[ -d "$ROOT" ] || { echo "ERROR: not a directory: $ROOT" >&2; exit 2; }
OUTDIR="./glbs"
mkdir -p "$OUTDIR"
ts="$(date +%Y%m%d_%H%M%S)"
log="link_glbs_${ts}.log"
# Make ROOT absolute and strip any trailing slash for consistent relpath math.
ROOT_ABS="$(cd "$ROOT" && pwd)"
ROOT_ABS="${ROOT_ABS%/}"
echo "ROOT: $ROOT_ABS" | tee "$log"
echo "OUTDIR: $(cd "$OUTDIR" && pwd)" | tee -a "$log"
echo "LOG: $log" | tee -a "$log"
echo "" | tee -a "$log"
# Sanitize: turn a path into a filesystem-safe basename.
# Example:
# Klicky-Probe/Printers/Voron/.../Dock_mount_fixed_v2.stl.glb
# becomes:
# Klicky-Probe__Printers__Voron__...__Dock_mount_fixed_v2.stl.glb
sanitize() {
# shellcheck disable=SC2001
echo "$1" \
| sed 's|^/||' \
| sed 's|/|__|g'
#| sed 's|/|__|g' \
#| sed 's|[^A-Za-z0-9._-]|_|g'
}
count=0
skipped=0
collisions=0
# Use -print0 to handle spaces safely.
find "$ROOT_ABS" -type f -name '*.glb' -print0 \
| while IFS= read -r -d '' f; do
# Compute relative path under ROOT_ABS
rel="${f#$ROOT_ABS/}"
name="$(sanitize "$rel")"
linkpath="$OUTDIR/$name"
# If the link exists and points to the same target, skip quietly.
if [ -L "$linkpath" ]; then
target="$(readlink "$linkpath" || true)"
if [ "$target" = "$f" ]; then
echo "SKIP (already linked): $linkpath -> $f" >> "$log"
skipped=$((skipped+1))
continue
fi
fi
# If the name already exists but points elsewhere, disambiguate.
if [ -e "$linkpath" ]; then
i=1
base="$linkpath"
while [ -e "$linkpath" ]; do
linkpath="${base%.glb}_$i.glb"
i=$((i+1))
done
collisions=$((collisions+1))
fi
ln -s "$f" "$linkpath"
echo "LINK: $linkpath -> $f" >> "$log"
count=$((count+1))
done
# The while loop runs in a subshell in many /bin/sh implementations,
# so counters above may not update. Summarize by counting log lines instead.
linked_lines="$(grep -c '^LINK: ' "$log" 2>/dev/null || echo 0)"
skipped_lines="$(grep -c '^SKIP ' "$log" 2>/dev/null || echo 0)"
echo "" | tee -a "$log"
echo "DONE. linked=$linked_lines skipped=$skipped_lines (details in $log)" | tee -a "$log"