From 813530ae48c234c64b0585cbe7063a4bea5295bd Mon Sep 17 00:00:00 2001 From: Darcy Wong Date: Tue, 3 Feb 2026 08:04:36 +0700 Subject: [PATCH 1/3] chore: Attempt to cache source if external source missing If external source is unavailable, get the latest version from downloads.keyman --- resources/external.inc.sh | 40 ++++++++++++++++++++++++++++++++++++++- tools/jq.inc.sh | 32 +++++++++++++++++++++++++++++++ 2 files changed, 71 insertions(+), 1 deletion(-) create mode 100755 tools/jq.inc.sh diff --git a/resources/external.inc.sh b/resources/external.inc.sh index 8e43b785..721c5bab 100644 --- a/resources/external.inc.sh +++ b/resources/external.inc.sh @@ -3,6 +3,8 @@ # This file corresponds very closely to external.inc.sh in keymanapp/keyboards #---------------------------------------------------------------------------------------- +. "./tools/jq.inc.sh" + retrieve_external_model() { # Assume we are starting in the correct folder [ -f external_source ] || die "No external_source file found" @@ -108,8 +110,44 @@ retrieve_external_binary_model() { [[ $filename =~ ^/ ]] && die "path cannot start with /" local path= [[ ! $filename =~ .model_info$ ]] && path=source/ - curl -s -L "$url" --output "$path$filename" --create-dirs || die "Unable to download $filename" + curl -s -L "$url" --output "$path$filename" --create-dirs || retrieve_cached_model "$path" "$filename" && continue echo "$sha256 $path$filename" | sha256sum -c --quiet || die "Invalid checksum for $filename" done < external_source } +# +# Download cached file from downloads.keyman when external source is missing +# +retrieve_cached_model() { + local path="$1" + local filename="$2" + builder_warn "Unable to download $filename so getting cached file from downloads.keyman.com" + + local extension="${filename##*.}" + local model_id="${filename%.model*}" + + local query="https://api.keyman.com/model/?q=${model_id}" + case "$extension" in + js) + local js_filename=`curl "$query" | $JQ -r '.[].jsFilename'` + curl -s -L "$js_filename" --output "$path$filename" --create-dirs || die "Unable to download $js_filename" + ;; + kmp) + local kmp_filename=`curl "$query" | $JQ -r '.[].packageFilename'` + curl -s -L "$kmp_filename" --output "$path$filename" --create-dirs || die "Unable to download $kmp_filename" + + # Also handle model_info since we need to query the latest version + # .model_info is downloaded up a level + local version=`curl "$query" | $JQ -r '.[].version'` + local model_info_filename="https://downloads.keyman.com/models/${model_id}/${version}/${model_id}.model_info" + curl -s -L "$model_info_filename" --output "$model_id.model_info" --create-dirs || die "Unable to download $model_info_filename" + ;; + model_info) + # Skip - handled above + echo "$filename handled elsewhere" + ;; + *) + die "$path $filename had unexpected extension (expecting js, kmp, or model_info)" + ;; + esac +} diff --git a/tools/jq.inc.sh b/tools/jq.inc.sh new file mode 100755 index 00000000..32c7b531 --- /dev/null +++ b/tools/jq.inc.sh @@ -0,0 +1,32 @@ +#!/usr/bin/env bash +# +# Setup JQ environment variable according to the user's system +# +# Windows: ./jq-win64.exe +# Linux/macOS: jq +# + +## START STANDARD BUILD SCRIPT INCLUDE +# adjust relative paths as necessary +JQ_THIS_SCRIPT="$(readlink -f "${BASH_SOURCE[0]}")" +# . "${THIS_SCRIPT%/*}/build-utils.sh" +## END STANDARD BUILD SCRIPT INCLUDE + +case "${OSTYPE}" in + "cygwin") + JQ=$(dirname "$JQ_THIS_SCRIPT")/jq-win64.exe + ;; + "msys") + JQ=$(dirname "$JQ_THIS_SCRIPT")/jq-win64.exe + ;; + *) + JQ=jq + ;; +esac + +readonly JQ + +# JQ with inplace file replacement +function jqi() { + cat <<< "$($JQ -c "$1" < "$2")" > "$2" +} From 62d08b999393503114ac0aaf91eca880f1f34b6c Mon Sep 17 00:00:00 2001 From: Darcy Wong Date: Wed, 4 Feb 2026 07:22:33 +0700 Subject: [PATCH 2/3] fix: Address review comments * Remove continue, process model_info in its own section --- bash.exe.stackdump | 28 ++++++++++++++++++++++++++++ resources/external.inc.sh | 12 ++++-------- 2 files changed, 32 insertions(+), 8 deletions(-) create mode 100644 bash.exe.stackdump diff --git a/bash.exe.stackdump b/bash.exe.stackdump new file mode 100644 index 00000000..3e1f717e --- /dev/null +++ b/bash.exe.stackdump @@ -0,0 +1,28 @@ +Stack trace: +Frame Function Args +0007FFFFC270 00021006118E (00021028DEE8, 000210272B3E, 000000000000, 0007FFFFB170) msys-2.0.dll+0x2118E +0007FFFFC270 0002100469BA (000000000000, 000000000000, 000000000000, 0007FFFFC548) msys-2.0.dll+0x69BA +0007FFFFC270 0002100469F2 (00021028DF99, 0007FFFFC128, 000000000000, 000000000000) msys-2.0.dll+0x69F2 +0007FFFFC270 00021006A41E (000000000000, 000000000000, 000000000000, 000000000000) msys-2.0.dll+0x2A41E +0007FFFFC270 00021006A545 (0007FFFFC280, 000000000000, 000000000000, 000000000000) msys-2.0.dll+0x2A545 +0007FFFFC550 00021006B9A5 (0007FFFFC280, 000000000000, 000000000000, 000000000000) msys-2.0.dll+0x2B9A5 +End of stack trace +Loaded modules: +000100400000 bash.exe +7FFB8AF60000 ntdll.dll +7FFB88E70000 KERNEL32.DLL +7FFB88900000 KERNELBASE.dll +7FFB88F40000 USER32.dll +7FFB888D0000 win32u.dll +000210040000 msys-2.0.dll +7FFB88E40000 GDI32.dll +7FFB88650000 gdi32full.dll +7FFB880B0000 msvcp_win.dll +7FFB88780000 ucrtbase.dll +7FFB8A1F0000 advapi32.dll +7FFB88D80000 msvcrt.dll +7FFB8AE00000 sechost.dll +7FFB8AAB0000 RPCRT4.dll +7FFB877B0000 CRYPTBASE.DLL +7FFB885A0000 bcryptPrimitives.dll +7FFB8A2B0000 IMM32.DLL diff --git a/resources/external.inc.sh b/resources/external.inc.sh index 721c5bab..3ae84786 100644 --- a/resources/external.inc.sh +++ b/resources/external.inc.sh @@ -110,7 +110,7 @@ retrieve_external_binary_model() { [[ $filename =~ ^/ ]] && die "path cannot start with /" local path= [[ ! $filename =~ .model_info$ ]] && path=source/ - curl -s -L "$url" --output "$path$filename" --create-dirs || retrieve_cached_model "$path" "$filename" && continue + curl -s -L "$url" --output "$path$filename" --create-dirs || retrieve_cached_model "$path" "$filename" echo "$sha256 $path$filename" | sha256sum -c --quiet || die "Invalid checksum for $filename" done < external_source } @@ -135,17 +135,13 @@ retrieve_cached_model() { kmp) local kmp_filename=`curl "$query" | $JQ -r '.[].packageFilename'` curl -s -L "$kmp_filename" --output "$path$filename" --create-dirs || die "Unable to download $kmp_filename" - - # Also handle model_info since we need to query the latest version - # .model_info is downloaded up a level + ;; + model_info) + # .model_info is downloaded up a level (not at $path) local version=`curl "$query" | $JQ -r '.[].version'` local model_info_filename="https://downloads.keyman.com/models/${model_id}/${version}/${model_id}.model_info" curl -s -L "$model_info_filename" --output "$model_id.model_info" --create-dirs || die "Unable to download $model_info_filename" ;; - model_info) - # Skip - handled above - echo "$filename handled elsewhere" - ;; *) die "$path $filename had unexpected extension (expecting js, kmp, or model_info)" ;; From cd889024ccae025e0208b9f2c642ae15a4cb2d38 Mon Sep 17 00:00:00 2001 From: Darcy Wong Date: Wed, 4 Feb 2026 13:58:40 +0700 Subject: [PATCH 3/3] chore: remove stray file --- bash.exe.stackdump | 28 ---------------------------- 1 file changed, 28 deletions(-) delete mode 100644 bash.exe.stackdump diff --git a/bash.exe.stackdump b/bash.exe.stackdump deleted file mode 100644 index 3e1f717e..00000000 --- a/bash.exe.stackdump +++ /dev/null @@ -1,28 +0,0 @@ -Stack trace: -Frame Function Args -0007FFFFC270 00021006118E (00021028DEE8, 000210272B3E, 000000000000, 0007FFFFB170) msys-2.0.dll+0x2118E -0007FFFFC270 0002100469BA (000000000000, 000000000000, 000000000000, 0007FFFFC548) msys-2.0.dll+0x69BA -0007FFFFC270 0002100469F2 (00021028DF99, 0007FFFFC128, 000000000000, 000000000000) msys-2.0.dll+0x69F2 -0007FFFFC270 00021006A41E (000000000000, 000000000000, 000000000000, 000000000000) msys-2.0.dll+0x2A41E -0007FFFFC270 00021006A545 (0007FFFFC280, 000000000000, 000000000000, 000000000000) msys-2.0.dll+0x2A545 -0007FFFFC550 00021006B9A5 (0007FFFFC280, 000000000000, 000000000000, 000000000000) msys-2.0.dll+0x2B9A5 -End of stack trace -Loaded modules: -000100400000 bash.exe -7FFB8AF60000 ntdll.dll -7FFB88E70000 KERNEL32.DLL -7FFB88900000 KERNELBASE.dll -7FFB88F40000 USER32.dll -7FFB888D0000 win32u.dll -000210040000 msys-2.0.dll -7FFB88E40000 GDI32.dll -7FFB88650000 gdi32full.dll -7FFB880B0000 msvcp_win.dll -7FFB88780000 ucrtbase.dll -7FFB8A1F0000 advapi32.dll -7FFB88D80000 msvcrt.dll -7FFB8AE00000 sechost.dll -7FFB8AAB0000 RPCRT4.dll -7FFB877B0000 CRYPTBASE.DLL -7FFB885A0000 bcryptPrimitives.dll -7FFB8A2B0000 IMM32.DLL