name: "Create OSK Files" description: "Create .osk archives for changed skins (safe handling of input JSON path)" inputs: changed_skins_file: description: "Path to file containing JSON array (changed skins)" required: false default: "" runs: using: "composite" steps: - name: Create OSK Files shell: bash run: | set -euo pipefail echo "[OSK Creation Job Started]" # Determine the changed skins file path from input or environment CHANGED_SKINS_FILE="${{ inputs.changed_skins_file }}" if [ -z "${CHANGED_SKINS_FILE:-}" ]; then CHANGED_SKINS_FILE="${CHANGED_SKINS_FILE:-${CHANGED_SKINS_FILE_ENV:-}}" fi # Allow workflow to pass CHANGED_SKINS_FILE via environment too if [ -z "${CHANGED_SKINS_FILE:-}" ] && [ -n "${CHANGED_SKINS_FILE:-}" ]; then CHANGED_SKINS_FILE="${CHANGED_SKINS_FILE}" fi # Fallback to common temp path if caller wrote there if [ -z "${CHANGED_SKINS_FILE:-}" ]; then if [ -f "/tmp/changed_skins.json" ]; then CHANGED_SKINS_FILE="/tmp/changed_skins.json" elif [ -f "/tmp/changed_skins.txt" ]; then CHANGED_SKINS_FILE="/tmp/changed_skins.txt" fi fi if [ -z "${CHANGED_SKINS_FILE:-}" ] || [ ! -s "$CHANGED_SKINS_FILE" ]; then echo "No skins changed or changed-skins file missing at: ${CHANGED_SKINS_FILE:-}". echo "Skipping OSK creation." exit 0 fi # Create a safe list file to avoid any template expansion / parsing surprises temp_list_file="/tmp/osk_skins_list_$RANDOM.txt" # If file is JSON array, extract with jq; if it's plain newline list, copy as-is if jq -e . >/dev/null 2>&1 < "$CHANGED_SKINS_FILE"; then jq -r '.[]' "$CHANGED_SKINS_FILE" > "$temp_list_file" else # treat as newline-separated cp "$CHANGED_SKINS_FILE" "$temp_list_file" fi # read into array mapfile -t skin_dirs < "$temp_list_file" rm -f "$temp_list_file" if [ "${#skin_dirs[@]}" -eq 0 ]; then echo "No skins to process. Exiting."; exit 0; fi sanitize_filename() { echo "$1" | \ tr -d '\000-\037' | \ sed -e 's#[\\/:\*\?"<>|]#-#g' | \ sed -e 's/^[[:space:]]*//' -e 's/[[:space:]]*$//' } FIXED_TIMESTAMP="2025-01-01 00:00:00" SKIN_COUNT=${#skin_dirs[@]} INDEX=1 for skin_path in "${skin_dirs[@]}"; do # skip empty lines [ -z "${skin_path}" ] && { ((INDEX++)); continue; } SKIN_DIR="${DANSER_SKINS_DIR:-$DANSER_SKINS_DIR}/${skin_path}" if [ ! -d "$SKIN_DIR" ]; then # try without prefix if caller passed full path if [ -d "$skin_path" ]; then SKIN_DIR="$skin_path" else echo "Skipping missing skin directory: $SKIN_DIR" ((INDEX++)) continue fi fi OUTPUT_DIR="${OSK_PATH:-/tmp/osk_out}/$skin_path" mkdir -p "$OUTPUT_DIR" skin_header="$skin_path" ini_file=$(find "$SKIN_DIR" -maxdepth 1 -type f -iname "skin.ini" -print -quit || true) if [ -f "$ini_file" ]; then name_line=$(grep -i '^[[:space:]]*name:' "$ini_file" | head -n1 || true) if [ -n "$name_line" ]; then val="${name_line#*:}" val="$(echo "$val" | sed 's/^[[:space:]]*//;s/[[:space:]]*$//')" if [ -n "$val" ]; then sanitized="$(sanitize_filename "$val")" [ -n "$sanitized" ] && skin_header="$sanitized" fi fi fi echo "" echo "[$INDEX/$SKIN_COUNT] Processing skin: $skin_header" # normalize timestamps to make builds deterministic (cd "$SKIN_DIR" && find . -type f -print0 | xargs -0 -I '{}' touch -d "$FIXED_TIMESTAMP" '{}') || true # Create a sorted file list to feed to zip (filenames may contain spaces/parentheses) filelist_tmp="/tmp/osk_files_$RANDOM.txt" (cd "$SKIN_DIR" && find . -type f -print0 | while IFS= read -r -d '' f; do printf '%s\n' "$f"; done | sort) > "$filelist_tmp" # Use zip reading names from file (-@) - convert to newline separated safe list # zip reads stdin; we provide list via input redirection (cd "$SKIN_DIR" && cat "$filelist_tmp" | zip -q -X -@ "$OUTPUT_DIR/${skin_header}.osk") rm -f "$filelist_tmp" echo " ✓ OSK file created at $OUTPUT_DIR/${skin_header}.osk" INDEX=$((INDEX + 1)) done echo "" echo "[OSK Creation Job Finished — processed $SKIN_COUNT skins]"