From 9f1ad23a187a493ffa812064e6641061553e6386 Mon Sep 17 00:00:00 2001 From: "Danilo M." Date: Mon, 18 May 2026 10:49:06 +0200 Subject: feat: multiline DOWNLOAD support, test suite, updated docs - Add parse_multiline_var, prompt_continuation_urls, build_multiline_value, _process_download_var; refactor update_checksums to handle multi-URL vars - First URL always re-downloaded; continuation URLs prompt user, skip re-download if unchanged - Add tests/mkhint_test.sh: 44 cases covering all commands and edge cases - Update README and CLAUDE.md: correct -N semantics, --new behavior, multiline DOWNLOAD flow, test suite docs --- mkhint | 148 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 135 insertions(+), 13 deletions(-) (limited to 'mkhint') diff --git a/mkhint b/mkhint index 9d307f5..62e6d05 100755 --- a/mkhint +++ b/mkhint @@ -218,25 +218,147 @@ add_nodownload() { fi } +# Parse multiline variable value (handles \ continuation lines) +# Prints each whitespace-separated token on its own line +parse_multiline_var() { + local varname="$1" + local file="$2" + # Join continuation lines, strip variable name and quotes, print one token per line + awk -v var="${varname}" ' + BEGIN { found=0; buf="" } + !found && $0 ~ "^"var"=\"" { + found=1 + buf=$0 + sub("^"var"=\"", "", buf) + if (buf !~ /\\[[:space:]]*$/) { + gsub(/"[[:space:]]*$/, "", buf) + n=split(buf, arr, /[[:space:]]+/) + for (k=1;k<=n;k++) if(arr[k]!="") print arr[k] + found=0; buf="" + } else { + gsub(/\\[[:space:]]*$/, "", buf) + } + next + } + found { + if ($0 ~ /\\[[:space:]]*$/) { + line=$0; gsub(/\\[[:space:]]*$/, "", line) + buf=buf" "line + } else { + line=$0; gsub(/"[[:space:]]*$/, "", line) + buf=buf" "line + n=split(buf, arr, /[[:space:]]+/) + for (k=1;k<=n;k++) if(arr[k]!="") print arr[k] + found=0; buf="" + } + } + ' "$file" +} + +# Prompt user for updated continuation URLs; returns updated URLs via nameref array +# First URL is always kept as-is (already updated by version sed before this call) +prompt_continuation_urls() { + local -n _urls="$1" # nameref: array of current URLs + local varname="$2" + + local i + for (( i=1; i<${#_urls[@]}; i++ )); do + local current="${_urls[$i]}" + echo "" + echo " ${varname} line $((i+1)) (current): $current" + read -r -p " New URL (leave blank to keep): " new_url + if [[ -n "$new_url" ]]; then + _urls[$i]="$new_url" + fi + done +} + +# Build multiline variable string for writing back to file +# Usage: build_multiline_value urls_array -> prints quoted multiline value +build_multiline_value() { + local -n _arr="$1" + local count=${#_arr[@]} + local i + for (( i=0; i 1 )); then + echo "" + echo "Multiline ${dl_var} detected in $(basename "$file")." + prompt_continuation_urls urls "$dl_var" fi + + # Download and calculate md5 for each URL + local new_md5s=() + local i + for (( i=0; i<${#urls[@]}; i++ )); do + local url="${urls[$i]}" + if (( i == 0 )); then + # Always re-download first URL + echo "Downloading: $url" + new_md5s+=( "$(download_file "$url")" ) + else + # Only re-download if URL changed from original + if [[ "$url" != "${orig_urls[$i]}" ]]; then + echo "Downloading (updated): $url" + new_md5s+=( "$(download_file "$url")" ) + else + echo "Keeping existing md5 for: $url" + new_md5s+=( "${md5s[$i]}" ) + fi + fi + done + + # Rebuild and write back DOWNLOAD variable (may have updated continuation URLs) + local new_dl_value + new_dl_value=$(build_multiline_value urls) + # Strip surrounding quotes — perl wraps them in the substitution + new_dl_value="${new_dl_value#\"}" + new_dl_value="${new_dl_value%\"}" + perl -i -0pe 'BEGIN{$v=shift} s|^'"${dl_var}"'="[^"]*(?:\\\n[^"]*)*"|'"${dl_var}"'="$v"|m' \ + "$new_dl_value" "$file" + + # Rebuild and write back MD5SUM variable + local new_md5_value + new_md5_value=$(build_multiline_value new_md5s) + new_md5_value="${new_md5_value#\"}" + new_md5_value="${new_md5_value%\"}" + perl -i -0pe 'BEGIN{$v=shift} s|^'"${md5_var}"'="[^"]*(?:\\\n[^"]*)*"|'"${md5_var}"'="$v"|m' \ + "$new_md5_value" "$file" } # Update existing hint file -- cgit v1.2.3