diff --git a/.github/workflows/auto-merge-keyman-server-pr.yml b/.github/workflows/auto-merge-keyman-server-pr.yml index 771fd6ae5e..bc1759f6bc 100644 --- a/.github/workflows/auto-merge-keyman-server-pr.yml +++ b/.github/workflows/auto-merge-keyman-server-pr.yml @@ -13,7 +13,7 @@ on: jobs: build: runs-on: ubuntu-latest - if: ${{ github.repository == 'keymanapp/keyman' && github.actor == 'keyman-server' && startsWith(github.event.pull_request.title, 'auto:') }} + if: ${{ github.repository == 'keymanapp/keyman' && github.actor == 'keyman-server' && startsWith(github.head_ref, 'auto/') }} steps: - name: auto approve PR from keyman-server shell: bash @@ -23,7 +23,6 @@ jobs: gh pr review -R keymanapp/keyman --approve ${{ github.event.pull_request.number }} - name: mark PR for auto-merge from keyman-server shell: bash - if: contains(github.event.pull_request.labels.*.name, 'automerge') env: GH_TOKEN: "${{ secrets.AUTOINC_GITHUB_TOKEN }}" run: | diff --git a/.github/workflows/npm-publish.yml b/.github/workflows/npm-publish.yml new file mode 100644 index 0000000000..fc94cc688e --- /dev/null +++ b/.github/workflows/npm-publish.yml @@ -0,0 +1,153 @@ +# +# Keyman is copyright (C) SIL Global. MIT License. +# +# Created by mcdurdin on 2025-10-27 +# +# This workflow publishes all our npm packages using Trusted Publishers OIDC +# permissions. It is triggered by a repository_dispatch event with the types +# `npm-publish:*`, from the trigger-builds infrastructure. For test builds, this +# does a `npm pack` only. +# +# Inputs: +# buildSha: The SHA of the commit to build, e.g. of the branch or +# refs/pull/1234/head for PR +# user: The user that triggered the build or created the PR +# isTestBuild: false for Releases, otherwise true + +name: "npm pack/publish" +run-name: "npm pack/publish - branch: ${{ github.event.client_payload.branch }} sha: ${{ github.event.client_payload.buildSha }}, user: @${{ github.event.client_payload.user }}, isTestBuild: ${{ github.event.client_payload.isTestBuild }}" +on: + repository_dispatch: + types: ['npm-publish:*'] + +permissions: + id-token: write # Required for OIDC + contents: read + statuses: write + +env: + GH_TOKEN: ${{ github.token }} + STATUS_CONTEXT: 'npm pack/publish' + IS_TEST_BUILD: ${{ github.event.client_payload.isTestBuild }} + # This property causes node.inc.sh to skip invocation of nvm, as otherwise, we + # end up downgrading to node v20 as of Keyman 19. See #15040 and corresponding + # change in node.inc.sh; we should be able to remove this in Keyman 20. + KEYMAN_CI_SKIP_NVM: true + +jobs: + npm_publish: + name: Publish or pack @keymanapp packages + if: github.repository == 'keymanapp/keyman' || github.event.client_payload.force + runs-on: ubuntu-24.04 + steps: + + - name: Set env var for pack vs publish + run: | + if [[ "$IS_TEST_BUILD" == true ]]; then + echo "NPM_ACTION=pack" >> $GITHUB_ENV + else + echo "NPM_ACTION=publish" >> $GITHUB_ENV + fi + + - name: Checkout + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 #v4.2.2 + with: + ref: '${{ github.event.client_payload.buildSha }}' + + - name: Set pending status + id: set_status + if: github.event.client_payload.isTestBuild == 'true' + shell: bash + run: | + gh api \ + --method POST \ + -H "Accept: application/vnd.github+json" \ + /repos/$GITHUB_REPOSITORY/statuses/${{ github.event.client_payload.buildSha }} \ + -f state='pending' \ + -f target_url="$GITHUB_SERVER_URL/$GITHUB_REPOSITORY/actions/runs/$GITHUB_RUN_ID" \ + -f description="npm $NPM_ACTION started" \ + -f context="$STATUS_CONTEXT" + + - name: Report initial npm/node versions + run: | + echo "Initial npm/node versions" + npm -v + node -v + + - uses: actions/setup-node@v6 + with: + node-version: '24.10' + + - name: Report current npm/node versions + run: | + echo "Current npm/node versions" + npm -v + node -v + + - name: Configure build environment + run: | + ./resources/build/ci/npm-publish.sh configure + + - name: npm pack/publish + run: | + export KEYMAN_TIER=$(cat TIER.md) + export GHA_TEST_BUILD="${{ github.event.client_payload.isTestBuild }}" + export GHA_BRANCH="${{ github.event.client_payload.branch }}" + echo "KEYMAN_TIER=$KEYMAN_TIER" >> $GITHUB_ENV + echo "GHA_TEST_BUILD=${GHA_TEST_BUILD}" >> $GITHUB_ENV + echo "GHA_BRANCH=${GHA_BRANCH}" >> $GITHUB_ENV + + echo "KEYMAN_TIER: $KEYMAN_TIER" + echo "GHA_TEST_BUILD: $GHA_TEST_BUILD" + echo "GHA_BRANCH: $GHA_BRANCH" + + if [[ -f ./resources/build/ci/npm-publish.sh ]]; then + ./resources/build/ci/npm-publish.sh $NPM_ACTION + else + echo WARNING: npm-publish.sh is not yet available + fi + + set_status: + name: Set result status on PR builds + needs: [npm_publish] + runs-on: ubuntu-latest + if: ${{ always() }} + steps: + + - name: Set env var for pack vs publish + run: | + if [[ "$IS_TEST_BUILD" == true ]]; then + echo "NPM_ACTION=pack" >> $GITHUB_ENV + else + echo "NPM_ACTION=publish" >> $GITHUB_ENV + fi + + - name: Set success + if: needs.npm_publish.result == 'success' + run: | + echo "RESULT=success" >> $GITHUB_ENV + echo "MSG=npm $NPM_ACTION succeeded" >> $GITHUB_ENV + + - name: Set cancelled + if: needs.npm_publish.result == 'cancelled' + run: | + echo "RESULT=error" >> $GITHUB_ENV + echo "MSG=npm $NPM_ACTION cancelled" >> $GITHUB_ENV + + - name: Set failure + if: needs.npm_publish.result == 'failure' + run: | + echo "RESULT=failure" >> $GITHUB_ENV + echo "MSG=npm $NPM_ACTION failed" >> $GITHUB_ENV + + - name: Set final status + if: github.event.client_payload.isTestBuild == 'true' + run: | + gh api \ + --method POST \ + -H "Accept: application/vnd.github+json" \ + /repos/$GITHUB_REPOSITORY/statuses/${{ github.event.client_payload.buildSha }} \ + -f state="$RESULT" \ + -f target_url="$GITHUB_SERVER_URL/$GITHUB_REPOSITORY/actions/runs/$GITHUB_RUN_ID" \ + -f description="$MSG" \ + -f context="$STATUS_CONTEXT" diff --git a/.github/workflows/pr-build-status.yml b/.github/workflows/pr-build-status.yml index 20d8007d9b..407dc23ef1 100644 --- a/.github/workflows/pr-build-status.yml +++ b/.github/workflows/pr-build-status.yml @@ -80,6 +80,8 @@ jobs: summary += addStatus(o, 'check', status.context, status.state); } else if(status.context == 'Ubuntu Packaging') { summary += addStatus(o, 'build', status.context, status.state); + } else if(status.context == 'npm pack/publish') { + summary += addStatus(o, 'build', status.context, status.state); } else if(status.context == 'check/web/file-size') { // Ignore check/web/file-size -- we won't block automerge for this at this point summary += addLog(`Skipping ${status.context}`); diff --git a/HISTORY.md b/HISTORY.md index cc860acc0b..9340e79af5 100644 --- a/HISTORY.md +++ b/HISTORY.md @@ -1,5 +1,78 @@ # Keyman Version History +## 19.0.157 alpha 2025-11-06 + +* chore(common): Consolidate platformtest.js keyboard to `/common/test/keyboards/` (#15034) +* chore(common): Consolidate test9469.js keyboard to `/common/test/keyboards/` (#15053) + +## 19.0.156 alpha 2025-11-05 + +* chore(linux): Update debian changelog (#14965) +* maint(resources): Docker container changes permissions to match the file owner uid and gid (#14900) +* fix(developer): remove package version if FollowKeyboardVersion is set in Package Editor (#15088) +* maint(windows): new timestamp server for test signing (#15091) + +## 19.0.155 alpha 2025-11-03 + +* maint(resources): auto merge on branch name rather than label (#15084) +* change(developer): remove kmlmc and kmlmp (#15083) + +## 19.0.154 alpha 2025-10-31 + +* chore(developer): further debugging for assertion failure (#15056) +* chore(developer): add breadcrumbs to trace sporadic crashes on exit (#15058) +* fix(developer): handle exceptions loading .keyman-touch-layout files (#15060) +* chore(developer): fix always-false nullish coalescing (#15061) +* chore(windows): upgrade VC++ projects to v143 (VS2022) (#15062) + +## 19.0.153 alpha 2025-10-30 + +* test(developer): add kmc-analyze tests for AnalyzeOskCharacterUse output formats (#15030) + +## 19.0.152 alpha 2025-10-30 + +* maint(resources): include sourcemaps in npm publish (#15051) + +## 19.0.151 alpha 2025-10-29 + +* maint(resources): add repository record for all published packages (#15049) + +## 19.0.150 alpha 2025-10-29 + +* maint(resources): set build flags for npm-publish (#15047) + +## 19.0.149 alpha 2025-10-29 + +* maint(resources): don't report status check on release builds for npm-publish (#15045) + +## 19.0.148 alpha 2025-10-29 + +* chore(web,android): Consolidate chirality.js test keyboard to `/common/test/resources/keyboards/` (#14989) +* maint(resources): npm publish - build all packages first (#15042) + +## 19.0.147 alpha 2025-10-28 + +* maint(resources): move npm package publishing to GitHub Actions (#15029) +* maint(resources): use actions/setup-node to upgrade npm (#15035) +* maint(resources): use a string for version, rather than number (#15036) +* maint(resources): set env variables in npm publish GHA (#15037) +* maint(mac): minor tweaks to mac setup, using build.sh (#15028) +* maint(resources): add build and test for npm packaging and add status check results (#15038) +* maint(resources): add write permission for statuses for npm-publish (#15039) +* maint(resources): skip nvm in npm-publish script (#15041) + +## 19.0.146 alpha 2025-10-27 + +* fix(mac): ignore non-Unicode key caps when preparing OSK (#15008) +* fix(developer): prevent ANSI keyboards crashing debugger (#15022) +* test(developer): add coverage tests for warning messages in kmc-analyze/AnalyzeOskCharacterUse (#15021) + +## 19.0.145 alpha 2025-10-24 + +* fix(developer): do not treat backslash as a string escape in syntax highlighting (#15001) +* fix(developer): handle missing `begin Unicode` in KMW compiler (#15002) +* test(developer): add test to kmc-analyze for Warn_PreviousMapFileCouldNotBeLoaded (#14038) + ## 19.0.144 alpha 2025-10-23 * chore(deps-dev): bump playwright from 1.46.1 to 1.56.1 (#14984) @@ -889,6 +962,17 @@ * refactor(windows): rename `TKeymanMutex.MutexOwned` to `TakeOwnership` and add `ReleaseOwnership` (#13168) * chore: increment to alpha 19.0 (#13187) +## 18.0.244 stable 2025-10-31 + +* fix(linux): use `ibus` command to restart ibus (#14975) +* fix(android): Set the main app background white (#14982) +* fix(developer): do not treat backslash as a string escape in syntax highlighting (#15005) +* fix(developer): handle missing `begin Unicode` in KMW compiler (#15006) +* fix(mac): ignore non-Unicode key caps when preparing OSK (#15009) +* maint(resources): move NPM package publishing to GitHub Actions (#15054) +* chore(developer): add breadcrumbs to trace sporadic crashes on exit (#15059) +* chore(developer): further debugging for assertion failure (#15057) + ## 18.0.243 stable 2025-10-15 * chore(linux): Update debian changelog (#14855) diff --git a/VERSION.md b/VERSION.md index d4ef205909..6823fd6611 100644 --- a/VERSION.md +++ b/VERSION.md @@ -1 +1 @@ -19.0.145 \ No newline at end of file +19.0.158 \ No newline at end of file diff --git a/android/Tests/KeyboardHarness/app/src/main/assets/keyboardharness.kmp b/android/Tests/KeyboardHarness/app/src/main/assets/keyboardharness.kmp index f0380aabe5..78366a42e5 100644 Binary files a/android/Tests/KeyboardHarness/app/src/main/assets/keyboardharness.kmp and b/android/Tests/KeyboardHarness/app/src/main/assets/keyboardharness.kmp differ diff --git a/android/Tests/KeyboardHarness/app/src/main/assets/keyboardharness.kpj b/android/Tests/KeyboardHarness/app/src/main/assets/keyboardharness.kpj index c7fa5c530c..80a3e1568a 100644 --- a/android/Tests/KeyboardHarness/app/src/main/assets/keyboardharness.kpj +++ b/android/Tests/KeyboardHarness/app/src/main/assets/keyboardharness.kpj @@ -1,56 +1,12 @@ + 2.0 $PROJECTPATH + $PROJECTPATH\ True - True True + True lexicalmodel - - - id_165fd1598b940efe4a973aeb6eb61aba - keyboardharness.kps - keyboardharness.kps - 1.0 - .kps -
- keyboardharness - ©2020 SIL International - 1.0 -
-
- - id_f9b1213d4e83cb32ce1ead1ee852d618 - chirality.js - ..\..\..\..\..\..\..\web\testing\chirality\chirality.js - - .js - id_165fd1598b940efe4a973aeb6eb61aba - - - id_e01841691fa129428aea555142873f69 - platformtest.js - ..\..\..\..\..\..\..\web\testing\platform\platformtest.js - - .js - id_165fd1598b940efe4a973aeb6eb61aba - - - id_03df89bb84a1aa6cab40dfebf3a04c5b - code2001.ttf - code2001.ttf - - .ttf - id_165fd1598b940efe4a973aeb6eb61aba - - - id_2d07bd2b8c94e9600ac1a920c8cb9e0a - longpress.js - longpress.js - - .js - id_165fd1598b940efe4a973aeb6eb61aba - -
diff --git a/android/Tests/KeyboardHarness/app/src/main/assets/keyboardharness.kps b/android/Tests/KeyboardHarness/app/src/main/assets/keyboardharness.kps index 157aefd71c..f18aac7a8e 100644 --- a/android/Tests/KeyboardHarness/app/src/main/assets/keyboardharness.kps +++ b/android/Tests/KeyboardHarness/app/src/main/assets/keyboardharness.kps @@ -20,17 +20,23 @@ - ..\..\..\..\..\..\..\web\src\test\manual\web\chirality\chirality.js + ../../../../../../../common/test/resources/keyboards/chirality.js File chirality.js 0 .js - ..\..\..\..\..\..\..\web\src\test\manual\web\platform\platformtest.js + ../../../../../../../common/test/keyboards/platform-rules/platformtest.js File platformtest.js 0 .js + + ../../../../../../../common/test/keyboards/test9469/build/test9469.js + File test9469.js + 0 + .js + code2001.ttf Font Code2001 @@ -61,6 +67,14 @@ English + + Test9469 + test9469 + 1.0 + + English + + longpress '"\|5% + longpress diff --git a/android/Tests/KeyboardHarness/app/src/main/assets/test9469.kmp b/android/Tests/KeyboardHarness/app/src/main/assets/test9469.kmp deleted file mode 100644 index 8390d5dee3..0000000000 Binary files a/android/Tests/KeyboardHarness/app/src/main/assets/test9469.kmp and /dev/null differ diff --git a/android/Tests/KeyboardHarness/app/src/main/java/com/keyman/android/tests/keyboardHarness/MainActivity.java b/android/Tests/KeyboardHarness/app/src/main/java/com/keyman/android/tests/keyboardHarness/MainActivity.java index 7b73341786..becec2868a 100644 --- a/android/Tests/KeyboardHarness/app/src/main/java/com/keyman/android/tests/keyboardHarness/MainActivity.java +++ b/android/Tests/KeyboardHarness/app/src/main/java/com/keyman/android/tests/keyboardHarness/MainActivity.java @@ -89,6 +89,21 @@ public class MainActivity extends BaseActivity implements OnKeyboardEventListene KMManager.KMDefault_KeyboardFont); KMManager.addKeyboard(this, platformtestKBbInfo); + // Issue #9469 Verify special characters in keyamnweb-osk.ttf keyboard + Keyboard specialKBInfo = new Keyboard( + "keyboardharness", + "test9469", + "test9469 Keyboard", + "en", + "English", + "1.0", + "", + "", + true, + KMManager.KMDefault_KeyboardFont, + KMManager.KMDefault_KeyboardFont); + KMManager.addKeyboard(this, specialKBInfo); + // Final K_ENTER test keyboard Keyboard finalKBInfo = new Keyboard( "final", @@ -103,21 +118,6 @@ public class MainActivity extends BaseActivity implements OnKeyboardEventListene KMManager.KMDefault_KeyboardFont, KMManager.KMDefault_KeyboardFont); KMManager.addKeyboard(this, finalKBInfo); - - // Issue #9469 Verify special characters in keyamnweb-osk.ttf keyboard - Keyboard specialKBInfo = new Keyboard( - "test9469", - "test9469", - "test9469 Keyboard", - "en", - "English", - "1.0", - "", - "", - true, - KMManager.KMDefault_KeyboardFont, - KMManager.KMDefault_KeyboardFont); - KMManager.addKeyboard(this, specialKBInfo); } @Override diff --git a/windows/src/test/manual-tests/platform-rules/platform-results.xlsx b/common/test/keyboards/platform-rules/platform-results.xlsx similarity index 100% rename from windows/src/test/manual-tests/platform-rules/platform-results.xlsx rename to common/test/keyboards/platform-rules/platform-results.xlsx diff --git a/common/test/keyboards/platform-rules/platformtest.js b/common/test/keyboards/platform-rules/platformtest.js new file mode 100644 index 0000000000..341447c7a8 --- /dev/null +++ b/common/test/keyboards/platform-rules/platformtest.js @@ -0,0 +1,499 @@ +if (typeof keyman === 'undefined') { + console.log('Keyboard requires KeymanWeb 10.0 or later'); + if (typeof tavultesoft !== 'undefined') tavultesoft.keymanweb.util.alert("This keyboard requires KeymanWeb 10.0 or later"); +} else { + KeymanWeb.KR(new Keyboard_platformtest()); +} + +function Keyboard_platformtest() { + this._v = (typeof keyman != "undefined" && typeof keyman.version == "string") ? parseInt(keyman.version, 10) : 9; + this.KI = "Keyboard_platformtest"; + this.KN = "PlatformTest"; + this.KMINVER = "10.0"; + this.KV = null; + this.KDU = 0; + this.KH = ''; + this.KM = 0; + this.KBVER = "1.0"; + this.KMBM = 0x0; + this.s20 = "touch"; + this.s21 = "hardware"; + this.s24 = "windows"; + this.s25 = "android"; + this.s26 = "ios"; + this.s27 = "macosx"; + this.s28 = "linux"; + this.s31 = "desktop"; + this.s32 = "tablet"; + this.s33 = "phone"; + this.s36 = "native"; + this.s37 = "web"; + this.s40 = "ie"; + this.s41 = "chrome"; + this.s42 = "edge"; + this.s43 = "firefox"; + this.s44 = "safari"; + this.s45 = "opera"; + this.s48 = "touch"; + this.s49 = "hardware"; + this.s52 = "platform-x"; + this.s55 = "WinDOWS"; + this.s56 = "ANDroid"; + this.s57 = "iOS"; + this.s58 = "macOSX"; + this.s59 = "LINUX"; + this.s61 = "touch"; + this.s62 = "hardware"; + this.s63 = "windows"; + this.s64 = "android"; + this.s65 = "ios"; + this.s66 = "macosx"; + this.s67 = "linux"; + this.s68 = "desktop"; + this.s69 = "tablet"; + this.s70 = "phone"; + this.s71 = "native"; + this.s72 = "web"; + this.s73 = "ie"; + this.s74 = "chrome"; + this.s75 = "edge"; + this.s76 = "firefox"; + this.s77 = "safari"; + this.s78 = "opera"; + this.s79 = "touch"; + this.s80 = "hardware"; + this.s81 = "platform-x"; + this.s82 = "WinDOWS"; + this.s83 = "ANDroid"; + this.s84 = "iOS"; + this.s85 = "macOSX"; + this.s86 = "LINUX"; + this.KVER = "18.0.241.0"; + this.KVS = []; + this.gs = function(t, e) { + return this.g0(t, e); + }; + this.gs = function(t, e) { + return this.g0(t, e); + }; + this.g0 = function(t, e) { + var k = KeymanWeb, + r = 0, + m = 0; + if (k.KKM(e, 16384, 65)) { + if (1) { + r = m = 1; + k.KDC(0, t); + r = this.g1(t, e); + m = 2; + } + } + if (!m && k.KIK(e)) { + r = 1; + k.KDC(-1, t); + r = this.g9(t, e); + m = 2; + } + return r; + }; + this.g1 = function(t, e) { + var k = KeymanWeb, + r = 1, + m = 0; + if (k.KIFS(31, this.s20, t)) { + m = 1; + k.KDC(0, t); + k.KO(-1, t, "touch"); + } else if (k.KIFS(31, this.s21, t)) { + m = 1; + k.KDC(0, t); + k.KO(-1, t, "hardware"); + } + if (m == 1) { + k.KDC(-1, t); + r = this.g2(t, e); + m = 2; + } + if (!m) { + k.KDC(-1, t); + k.KO(-1, t, "undefined"); + r = this.g2(t, e); + m = 2; + } + return r; + }; + this.g2 = function(t, e) { + var k = KeymanWeb, + r = 1, + m = 0; + if (k.KIFS(31, this.s24, t)) { + m = 1; + k.KDC(0, t); + k.KO(-1, t, " windows"); + } else if (k.KIFS(31, this.s25, t)) { + m = 1; + k.KDC(0, t); + k.KO(-1, t, " android"); + } else if (k.KIFS(31, this.s26, t)) { + m = 1; + k.KDC(0, t); + k.KO(-1, t, " ios"); + } else if (k.KIFS(31, this.s27, t)) { + m = 1; + k.KDC(0, t); + k.KO(-1, t, " macosx"); + } else if (k.KIFS(31, this.s28, t)) { + m = 1; + k.KDC(0, t); + k.KO(-1, t, " linux"); + } + if (m == 1) { + k.KDC(-1, t); + r = this.g3(t, e); + m = 2; + } + if (!m) { + k.KDC(-1, t); + k.KO(-1, t, " undefined"); + r = this.g3(t, e); + m = 2; + } + return r; + }; + this.g3 = function(t, e) { + var k = KeymanWeb, + r = 1, + m = 0; + if (k.KIFS(31, this.s31, t)) { + m = 1; + k.KDC(0, t); + k.KO(-1, t, " desktop"); + } else if (k.KIFS(31, this.s32, t)) { + m = 1; + k.KDC(0, t); + k.KO(-1, t, " tablet"); + } else if (k.KIFS(31, this.s33, t)) { + m = 1; + k.KDC(0, t); + k.KO(-1, t, " phone"); + } + if (m == 1) { + k.KDC(-1, t); + r = this.g4(t, e); + m = 2; + } + if (!m) { + k.KDC(-1, t); + k.KO(-1, t, " undefined"); + r = this.g4(t, e); + m = 2; + } + return r; + }; + this.g4 = function(t, e) { + var k = KeymanWeb, + r = 1, + m = 0; + if (k.KIFS(31, this.s36, t)) { + m = 1; + k.KDC(0, t); + k.KO(-1, t, " native"); + } else if (k.KIFS(31, this.s37, t)) { + m = 1; + k.KDC(0, t); + k.KO(-1, t, " web"); + } + if (m == 1) { + k.KDC(-1, t); + r = this.g5(t, e); + m = 2; + } + if (!m) { + k.KDC(-1, t); + k.KO(-1, t, " undefined"); + r = this.g5(t, e); + m = 2; + } + return r; + }; + this.g5 = function(t, e) { + var k = KeymanWeb, + r = 1, + m = 0; + if (k.KIFS(31, this.s40, t)) { + m = 1; + k.KDC(0, t); + k.KO(-1, t, " ie"); + } else if (k.KIFS(31, this.s41, t)) { + m = 1; + k.KDC(0, t); + k.KO(-1, t, " chrome"); + } else if (k.KIFS(31, this.s42, t)) { + m = 1; + k.KDC(0, t); + k.KO(-1, t, " edge"); + } else if (k.KIFS(31, this.s43, t)) { + m = 1; + k.KDC(0, t); + k.KO(-1, t, " firefox"); + } else if (k.KIFS(31, this.s44, t)) { + m = 1; + k.KDC(0, t); + k.KO(-1, t, " safari"); + } else if (k.KIFS(31, this.s45, t)) { + m = 1; + k.KDC(0, t); + k.KO(-1, t, " opera"); + } + if (m == 1) { + k.KDC(-1, t); + r = this.g6(t, e); + m = 2; + } + if (!m) { + k.KDC(-1, t); + k.KO(-1, t, " undefined"); + r = this.g6(t, e); + m = 2; + } + return r; + }; + this.g6 = function(t, e) { + var k = KeymanWeb, + r = 1, + m = 0; + if (!k.KIFS(31, this.s48, t)) { + m = 1; + k.KDC(0, t); + k.KO(-1, t, " !touch"); + } else if (!k.KIFS(31, this.s49, t)) { + m = 1; + k.KDC(0, t); + k.KO(-1, t, " !hardware"); + } + if (m == 1) { + k.KDC(-1, t); + r = this.g7(t, e); + m = 2; + } + if (!m) { + k.KDC(-1, t); + k.KO(-1, t, " undefined"); + r = this.g7(t, e); + m = 2; + } + return r; + }; + this.g7 = function(t, e) { + var k = KeymanWeb, + r = 1, + m = 0; + if (k.KIFS(31, this.s52, t)) { + m = 1; + k.KDC(0, t); + k.KO(-1, t, " platform-x"); + } + if (m == 1) { + k.KDC(-1, t); + r = this.g8(t, e); + m = 2; + } + if (!m) { + k.KDC(-1, t); + k.KO(-1, t, " undefined"); + r = this.g8(t, e); + m = 2; + } + return r; + }; + this.g8 = function(t, e) { + var k = KeymanWeb, + r = 1, + m = 0; + if (k.KIFS(31, this.s55, t)) { + m = 1; + k.KDC(0, t); + k.KO(-1, t, " windows"); + } else if (k.KIFS(31, this.s56, t)) { + m = 1; + k.KDC(0, t); + k.KO(-1, t, " android"); + } else if (k.KIFS(31, this.s57, t)) { + m = 1; + k.KDC(0, t); + k.KO(-1, t, " ios"); + } else if (k.KIFS(31, this.s58, t)) { + m = 1; + k.KDC(0, t); + k.KO(-1, t, " macosx"); + } else if (k.KIFS(31, this.s59, t)) { + m = 1; + k.KDC(0, t); + k.KO(-1, t, " linux"); + } + if (!m) { + k.KDC(-1, t); + k.KO(-1, t, " undefined"); + } + return r; + }; + this.g9 = function(t, e) { + var k = KeymanWeb, + r = 0, + m = 0; + if (k.KKM(e, 16384, 69)) { + if (k.KIFS(31, this.s82, t)) { + r = m = 1; + k.KDC(0, t); + k.KO(-1, t, " Windows"); + } else if (k.KIFS(31, this.s83, t)) { + r = m = 1; + k.KDC(0, t); + k.KO(-1, t, " Android"); + } else if (k.KIFS(31, this.s84, t)) { + r = m = 1; + k.KDC(0, t); + k.KO(-1, t, " iOS"); + } else if (k.KIFS(31, this.s85, t)) { + r = m = 1; + k.KDC(0, t); + k.KO(-1, t, " macOS"); + } else if (k.KIFS(31, this.s86, t)) { + r = m = 1; + k.KDC(0, t); + k.KO(-1, t, " Linux"); + } else if (1) { + r = m = 1; + k.KDC(0, t); + k.KO(-1, t, " [OS Undefined (case insensitive test)]"); + } + } else if (k.KKM(e, 16384, 73)) { + if (k.KIFS(31, this.s68, t)) { + r = m = 1; + k.KDC(0, t); + k.KO(-1, t, " Desktop"); + } else if (k.KIFS(31, this.s69, t)) { + r = m = 1; + k.KDC(0, t); + k.KO(-1, t, " Tablet"); + } else if (k.KIFS(31, this.s70, t)) { + r = m = 1; + k.KDC(0, t); + k.KO(-1, t, " Phone"); + } else if (1) { + r = m = 1; + k.KDC(0, t); + k.KO(-1, t, " [FF Undefined]"); + } + } else if (k.KKM(e, 16384, 79)) { + if (k.KIFS(31, this.s63, t)) { + r = m = 1; + k.KDC(0, t); + k.KO(-1, t, " Windows"); + } else if (k.KIFS(31, this.s64, t)) { + r = m = 1; + k.KDC(0, t); + k.KO(-1, t, " Android"); + } else if (k.KIFS(31, this.s65, t)) { + r = m = 1; + k.KDC(0, t); + k.KO(-1, t, " iOS"); + } else if (k.KIFS(31, this.s66, t)) { + r = m = 1; + k.KDC(0, t); + k.KO(-1, t, " OSX"); + } else if (k.KIFS(31, this.s67, t)) { + r = m = 1; + k.KDC(0, t); + k.KO(-1, t, " Linux"); + } else if (1) { + r = m = 1; + k.KDC(0, t); + k.KO(-1, t, " [OS Undefined]"); + } + } else if (k.KKM(e, 16384, 80)) { + if (k.KIFS(31, this.s61, t)) { + r = m = 1; + k.KDC(0, t); + k.KO(-1, t, "Touch"); + } else if (k.KIFS(31, this.s62, t)) { + r = m = 1; + k.KDC(0, t); + k.KO(-1, t, "Hardware"); + } else if (1) { + r = m = 1; + k.KDC(0, t); + k.KO(-1, t, "[UI Undefined]"); + } + } else if (k.KKM(e, 16384, 82)) { + if (k.KIFS(31, this.s81, t)) { + r = m = 1; + k.KDC(0, t); + k.KO(-1, t, " Platform-X"); + } else if (1) { + r = m = 1; + k.KDC(0, t); + k.KO(-1, t, " [Platform-X Undefined]"); + } + } else if (k.KKM(e, 16384, 84)) { + if (!k.KIFS(31, this.s79, t)) { + r = m = 1; + k.KDC(0, t); + k.KO(-1, t, " !Touch"); + } else if (!k.KIFS(31, this.s80, t)) { + r = m = 1; + k.KDC(0, t); + k.KO(-1, t, " !Hardware"); + } else if (1) { + r = m = 1; + k.KDC(0, t); + k.KO(-1, t, " [Inverted OS Undefined]"); + } + } else if (k.KKM(e, 16384, 85)) { + if (k.KIFS(31, this.s71, t)) { + r = m = 1; + k.KDC(0, t); + k.KO(-1, t, " Native"); + } else if (k.KIFS(31, this.s72, t)) { + r = m = 1; + k.KDC(0, t); + k.KO(-1, t, " Web"); + } else if (1) { + r = m = 1; + k.KDC(0, t); + k.KO(-1, t, " [Nativeness Undefined]"); + } + } else if (k.KKM(e, 16384, 89)) { + if (k.KIFS(31, this.s73, t)) { + r = m = 1; + k.KDC(0, t); + k.KO(-1, t, " IE"); + } else if (k.KIFS(31, this.s74, t)) { + r = m = 1; + k.KDC(0, t); + k.KO(-1, t, " Chrome"); + } else if (k.KIFS(31, this.s75, t)) { + r = m = 1; + k.KDC(0, t); + k.KO(-1, t, " Edge"); + } else if (k.KIFS(31, this.s76, t)) { + r = m = 1; + k.KDC(0, t); + k.KO(-1, t, " Firefox"); + } else if (k.KIFS(31, this.s77, t)) { + r = m = 1; + k.KDC(0, t); + k.KO(-1, t, " Safari"); + } else if (k.KIFS(31, this.s78, t)) { + r = m = 1; + k.KDC(0, t); + k.KO(-1, t, " Opera"); + } else if (1) { + r = m = 1; + k.KDC(0, t); + k.KO(-1, t, " [Browser Undefined]"); + } + } + return r; + }; +} diff --git a/common/test/keyboards/platform-rules/platformtest.kmp b/common/test/keyboards/platform-rules/platformtest.kmp new file mode 100644 index 0000000000..ecef09c75c Binary files /dev/null and b/common/test/keyboards/platform-rules/platformtest.kmp differ diff --git a/common/test/keyboards/platform-rules/platformtest.kmx b/common/test/keyboards/platform-rules/platformtest.kmx new file mode 100644 index 0000000000..6d1ff7e97a Binary files /dev/null and b/common/test/keyboards/platform-rules/platformtest.kmx differ diff --git a/windows/src/test/manual-tests/platform-rules/platformtest.kpj b/common/test/keyboards/platform-rules/platformtest.kpj similarity index 79% rename from windows/src/test/manual-tests/platform-rules/platformtest.kpj rename to common/test/keyboards/platform-rules/platformtest.kpj index e476987511..447f7d86d7 100644 --- a/windows/src/test/manual-tests/platform-rules/platformtest.kpj +++ b/common/test/keyboards/platform-rules/platformtest.kpj @@ -4,22 +4,25 @@ False True + True + keyboard id_c1593d698cb624690005787147089dab platformtest.kmn - platformtest.kmn + source/platformtest.kmn 1.0 .kmn
PlatformTest + © SIL Global
id_18e336f9ad890bf821ff56e1a7764478 platformtest.kps - platformtest.kps + source/platformtest.kps .kps
@@ -28,8 +31,8 @@ id_61f04814d427ce02953436f3ea7d7a65 - PlatformTest.kmx - PlatformTest.kmx + platformtest.kmx + platformtest.kmx .kmx id_18e336f9ad890bf821ff56e1a7764478 diff --git a/windows/src/test/manual-tests/platform-rules/platformtest.kmn b/common/test/keyboards/platform-rules/source/platformtest.kmn similarity index 96% rename from windows/src/test/manual-tests/platform-rules/platformtest.kmn rename to common/test/keyboards/platform-rules/source/platformtest.kmn index b33fe0e763..490f569e3e 100644 --- a/windows/src/test/manual-tests/platform-rules/platformtest.kmn +++ b/common/test/keyboards/platform-rules/source/platformtest.kmn @@ -1,5 +1,8 @@ -store(&TARGETS) 'any' +store(&VERSION) '10.0' +store(&TARGETS) 'any' store(&NAME) 'PlatformTest' +store(&KEYBOARDVERSION) '1.0' +store(©RIGHT) '© SIL Global' begin Unicode > use(main) group(main) using keys diff --git a/common/test/keyboards/platform-rules/source/platformtest.kmp b/common/test/keyboards/platform-rules/source/platformtest.kmp new file mode 100644 index 0000000000..636859726f Binary files /dev/null and b/common/test/keyboards/platform-rules/source/platformtest.kmp differ diff --git a/common/test/keyboards/platform-rules/source/platformtest.kmx b/common/test/keyboards/platform-rules/source/platformtest.kmx new file mode 100644 index 0000000000..52d72993d0 Binary files /dev/null and b/common/test/keyboards/platform-rules/source/platformtest.kmx differ diff --git a/windows/src/test/manual-tests/platform-rules/platformtest.kps b/common/test/keyboards/platform-rules/source/platformtest.kps similarity index 81% rename from windows/src/test/manual-tests/platform-rules/platformtest.kps rename to common/test/keyboards/platform-rules/source/platformtest.kps index 825b0d5607..9a9186d5bb 100644 --- a/windows/src/test/manual-tests/platform-rules/platformtest.kps +++ b/common/test/keyboards/platform-rules/source/platformtest.kps @@ -17,16 +17,17 @@ PlatformTest + Test keyboard for displaying platform information. - PlatformTest.kmx - Keyboard PlatformTest + ../platformtest.kmx + Keyboard Platformtest 0 .kmx - platformtest.js + ../platformtest.js File platformtest.js 0 .js diff --git a/web/src/test/manual/web/issue9469/test9469/HISTORY.md b/common/test/keyboards/test9469/HISTORY.md similarity index 100% rename from web/src/test/manual/web/issue9469/test9469/HISTORY.md rename to common/test/keyboards/test9469/HISTORY.md diff --git a/web/src/test/manual/web/issue9469/test9469/LICENSE.md b/common/test/keyboards/test9469/LICENSE.md similarity index 100% rename from web/src/test/manual/web/issue9469/test9469/LICENSE.md rename to common/test/keyboards/test9469/LICENSE.md diff --git a/web/src/test/manual/web/issue9469/test9469/README.md b/common/test/keyboards/test9469/README.md similarity index 100% rename from web/src/test/manual/web/issue9469/test9469/README.md rename to common/test/keyboards/test9469/README.md diff --git a/web/src/test/manual/web/issue9469/test9469/build/test9469.js b/common/test/keyboards/test9469/build/test9469.js similarity index 100% rename from web/src/test/manual/web/issue9469/test9469/build/test9469.js rename to common/test/keyboards/test9469/build/test9469.js diff --git a/common/test/keyboards/test9469/build/test9469.kmp b/common/test/keyboards/test9469/build/test9469.kmp new file mode 100644 index 0000000000..00a111e260 Binary files /dev/null and b/common/test/keyboards/test9469/build/test9469.kmp differ diff --git a/common/test/keyboards/test9469/build/test9469.kmx b/common/test/keyboards/test9469/build/test9469.kmx new file mode 100644 index 0000000000..717a37dad3 Binary files /dev/null and b/common/test/keyboards/test9469/build/test9469.kmx differ diff --git a/common/test/keyboards/test9469/build/test9469.kvk b/common/test/keyboards/test9469/build/test9469.kvk new file mode 100644 index 0000000000..1f708b42b7 Binary files /dev/null and b/common/test/keyboards/test9469/build/test9469.kvk differ diff --git a/web/src/test/manual/web/issue9469/test9469/source/readme.htm b/common/test/keyboards/test9469/source/readme.htm similarity index 100% rename from web/src/test/manual/web/issue9469/test9469/source/readme.htm rename to common/test/keyboards/test9469/source/readme.htm diff --git a/web/src/test/manual/web/issue9469/test9469/source/test9469.ico b/common/test/keyboards/test9469/source/test9469.ico similarity index 100% rename from web/src/test/manual/web/issue9469/test9469/source/test9469.ico rename to common/test/keyboards/test9469/source/test9469.ico diff --git a/web/src/test/manual/web/issue9469/test9469/source/test9469.keyman-touch-layout b/common/test/keyboards/test9469/source/test9469.keyman-touch-layout similarity index 100% rename from web/src/test/manual/web/issue9469/test9469/source/test9469.keyman-touch-layout rename to common/test/keyboards/test9469/source/test9469.keyman-touch-layout diff --git a/web/src/test/manual/web/issue9469/test9469/source/test9469.kmn b/common/test/keyboards/test9469/source/test9469.kmn similarity index 96% rename from web/src/test/manual/web/issue9469/test9469/source/test9469.kmn rename to common/test/keyboards/test9469/source/test9469.kmn index d0f84c749a..cd90a48d70 100644 --- a/web/src/test/manual/web/issue9469/test9469/source/test9469.kmn +++ b/common/test/keyboards/test9469/source/test9469.kmn @@ -1,6 +1,6 @@ c test9469 generated from template at 2023-08-17 19:34:17 c with name "test9469" -store(&VERSION) '10.0' +store(&VERSION) '14.0' store(&NAME) 'test9469' store(©RIGHT) '© 2023 SIL International' store(&KEYBOARDVERSION) '1.1' diff --git a/web/src/test/manual/web/issue9469/test9469/source/test9469.kps b/common/test/keyboards/test9469/source/test9469.kps similarity index 93% rename from web/src/test/manual/web/issue9469/test9469/source/test9469.kps rename to common/test/keyboards/test9469/source/test9469.kps index 607e31751f..64c5231819 100644 --- a/web/src/test/manual/web/issue9469/test9469/source/test9469.kps +++ b/common/test/keyboards/test9469/source/test9469.kps @@ -20,6 +20,7 @@ © 2023 SIL International SIL International + Test keyboard for displaying special characters rendered with keymanweb-osk.ttf diff --git a/web/src/test/manual/web/issue9469/test9469/source/test9469.kvks b/common/test/keyboards/test9469/source/test9469.kvks similarity index 100% rename from web/src/test/manual/web/issue9469/test9469/source/test9469.kvks rename to common/test/keyboards/test9469/source/test9469.kvks diff --git a/web/src/test/manual/web/issue9469/test9469/source/welcome.htm b/common/test/keyboards/test9469/source/welcome.htm similarity index 100% rename from web/src/test/manual/web/issue9469/test9469/source/welcome.htm rename to common/test/keyboards/test9469/source/welcome.htm diff --git a/web/src/test/manual/web/issue9469/test9469/test9469.keyboard_info b/common/test/keyboards/test9469/test9469.keyboard_info similarity index 100% rename from web/src/test/manual/web/issue9469/test9469/test9469.keyboard_info rename to common/test/keyboards/test9469/test9469.keyboard_info diff --git a/web/src/test/manual/web/issue9469/test9469/test9469.kpj b/common/test/keyboards/test9469/test9469.kpj similarity index 100% rename from web/src/test/manual/web/issue9469/test9469/test9469.kpj rename to common/test/keyboards/test9469/test9469.kpj diff --git a/web/src/test/manual/web/chirality/chirality.js b/common/test/resources/keyboards/chirality.js similarity index 100% rename from web/src/test/manual/web/chirality/chirality.js rename to common/test/resources/keyboards/chirality.js diff --git a/common/web/keyman-version/build.sh b/common/web/keyman-version/build.sh index 781c63bbec..9e165e8662 100755 --- a/common/web/keyman-version/build.sh +++ b/common/web/keyman-version/build.sh @@ -7,7 +7,6 @@ THIS_SCRIPT="$(readlink -f "${BASH_SOURCE[0]}")" . "$KEYMAN_ROOT/resources/build/utils.inc.sh" . "$KEYMAN_ROOT/resources/build/node.inc.sh" -. "$KEYMAN_ROOT/resources/build/ci/ci-publish.inc.sh" ################################ Main script ################################ @@ -15,10 +14,7 @@ builder_describe "Build the include script for current Keyman version" \ configure \ clean \ build \ - test \ - "publish publish to npm" \ - "--npm-publish+ For publish, do a npm publish, not npm pack (only for CI)" \ - "--dry-run,-n don't actually publish, just dry run" + test builder_describe_outputs \ configure "/node_modules" \ @@ -56,4 +52,3 @@ export default KEYMAN_VERSION; builder_run_action clean rm -rf version.inc.ts keyman-version.mts build/ builder_run_action configure node_select_version_and_npm_ci builder_run_action build do_build -builder_run_action publish ci_publish_npm diff --git a/common/web/keyman-version/package.json b/common/web/keyman-version/package.json index 74cce896bd..891edbdb87 100644 --- a/common/web/keyman-version/package.json +++ b/common/web/keyman-version/package.json @@ -1,5 +1,10 @@ { "name": "@keymanapp/keyman-version", + "repository": { + "type": "git", + "url": "git+https://github.com/keymanapp/keyman.git", + "directory": "common/web/keyman-version" + }, "description": "Keyman global version data", "exports": { ".": { diff --git a/common/web/langtags/build.sh b/common/web/langtags/build.sh index 4eec3d2c6a..c4db9e1061 100755 --- a/common/web/langtags/build.sh +++ b/common/web/langtags/build.sh @@ -7,16 +7,12 @@ THIS_SCRIPT="$(readlink -f "${BASH_SOURCE[0]}")" . "$KEYMAN_ROOT/resources/build/utils.inc.sh" . "$KEYMAN_ROOT/resources/build/node.inc.sh" -. "$KEYMAN_ROOT/resources/build/ci/ci-publish.inc.sh" builder_describe "Build Keyman langtags.js common module" \ "clean" \ "configure" \ "build" \ - "test" \ - "publish publish to npm" \ - "--npm-publish+ For publish, do a npm publish, not npm pack (only for CI)" \ - "--dry-run,-n don't actually publish, just dry run" + "test" builder_describe_outputs \ configure /common/web/langtags/src/imports/langtags.js \ @@ -43,4 +39,3 @@ builder_run_action clean rm -rf ./build ./src/imports ./node_modules builder_run_action configure do_configure builder_run_action build tsc --build builder_run_action test echo 'no tests for langtags' -builder_run_action publish ci_publish_npm diff --git a/common/web/langtags/package.json b/common/web/langtags/package.json index f2848f587f..5746955d2d 100644 --- a/common/web/langtags/package.json +++ b/common/web/langtags/package.json @@ -33,7 +33,8 @@ }, "repository": { "type": "git", - "url": "git+https://github.com/keymanapp/keyman.git" + "url": "git+https://github.com/keymanapp/keyman.git", + "directory": "common/web/langtags" }, "sideEffects": false } diff --git a/common/web/types/build.sh b/common/web/types/build.sh index 518f531dd4..08419fa35d 100755 --- a/common/web/types/build.sh +++ b/common/web/types/build.sh @@ -8,7 +8,6 @@ THIS_SCRIPT="$(readlink -f "${BASH_SOURCE[0]}")" . "$KEYMAN_ROOT/resources/build/utils.inc.sh" . "$KEYMAN_ROOT/resources/build/node.inc.sh" . "$KEYMAN_ROOT/resources/build/typescript.inc.sh" -. "$KEYMAN_ROOT/resources/build/ci/ci-publish.inc.sh" builder_describe "Build Keyman common file types module" \ "@/core/include/ldml" \ @@ -16,10 +15,7 @@ builder_describe "Build Keyman common file types module" \ "configure" \ "build" \ "clean" \ - "test" \ - "publish publish to npm" \ - "--npm-publish+ For publish, do a npm publish, not npm pack (only for CI)" \ - "--dry-run,-n don't actually publish, just dry run" + "test" builder_describe_outputs \ configure /common/web/types/src/schemas/kpj.schema.ts \ @@ -87,4 +83,3 @@ builder_run_action clean rm -rf ./build/ ./tsconfig.tsbuildinfo ./src/schem builder_run_action configure do_configure builder_run_action build tsc --build builder_run_action test typescript_run_eslint_mocha_tests 60 -builder_run_action publish ci_publish_npm diff --git a/common/web/types/package.json b/common/web/types/package.json index d29766e567..4c987c6f0a 100644 --- a/common/web/types/package.json +++ b/common/web/types/package.json @@ -54,7 +54,8 @@ }, "repository": { "type": "git", - "url": "git+https://github.com/keymanapp/keyman.git" + "url": "git+https://github.com/keymanapp/keyman.git", + "directory": "common/web/types" }, "c8": { "all": true, diff --git a/common/windows/delphi/packages/PackageInfo.pas b/common/windows/delphi/packages/PackageInfo.pas index 6be3bb82a9..7de369f957 100644 --- a/common/windows/delphi/packages/PackageInfo.pas +++ b/common/windows/delphi/packages/PackageInfo.pas @@ -455,6 +455,7 @@ type procedure DoSaveJSON(ARoot: TJSONObject); virtual; procedure DoLoadIni(ini: TIniFile); virtual; procedure DoSaveIni(ini: TIniFile); virtual; + procedure Cleanup; virtual; public Options: TPackageOptions; StartMenu: TPackageStartMenu; @@ -1889,11 +1890,18 @@ begin end; end; +procedure TPackage.Cleanup; +begin + // No op in basic package +end; + procedure TPackage.SaveXML; var doc: IXMLDocument; root: IXMLNode; begin + Cleanup; + doc := NewXMLDocument; doc.Encoding := 'utf-8'; @@ -1914,6 +1922,8 @@ var doc: IXMLDocument; root: IXMLNode; begin + Cleanup; + doc := NewXMLDocument; doc.Encoding := 'utf-8'; diff --git a/common/windows/signtime.bat b/common/windows/signtime.bat index 80eb4770ef..d29cf58b75 100644 --- a/common/windows/signtime.bat +++ b/common/windows/signtime.bat @@ -4,8 +4,8 @@ rem Build agents have a separate signtime script. We don't use 'call' here so rem executing that script will terminate this one. if exist c:\codesign\signtime.bat c:\codesign\signtime.bat %1 %2 %3 %4 %5 %6 %7 %8 -set SERVERLIST=(http://timestamp.comodoca.com/authenticode http://timestamp.verisign.com/scripts/timstamp.dll http://timestamp.globalsign.com/scripts/timestamp.dll http://tsa.starfieldtech.com) -set RFC3161SERVERLIST=(http://timestamp.comodoca.com/rfc3161) +set SERVERLIST=(http://timestamp.digicert.com http://timestamp.sectigo.com) +set RFC3161SERVERLIST=(http://timestamp.digicert.com http://timestamp.sectigo.com) set SIGNTOOL=%1 set PFX_SHA1=%2 set PFX_SHA256=%3 diff --git a/core/include/ldml/build.sh b/core/include/ldml/build.sh index 4029d732ce..8adf30773e 100755 --- a/core/include/ldml/build.sh +++ b/core/include/ldml/build.sh @@ -10,17 +10,13 @@ THIS_SCRIPT="$(readlink -f "${BASH_SOURCE[0]}")" . "$KEYMAN_ROOT/resources/build/utils.inc.sh" . "$KEYMAN_ROOT/resources/build/node.inc.sh" -. "$KEYMAN_ROOT/resources/build/ci/ci-publish.inc.sh" builder_describe "Keyman ldml-keyboard-constants package" \ "@/common/web/keyman-version" \ "clean" \ "configure" \ "build" \ - "test" \ - "publish publish to npm" \ - "--npm-publish+ For publish, do a npm publish, not npm pack (only for CI)" \ - "--dry-run,-n don't actually publish, just dry run" + "test" builder_describe_outputs \ configure /node_modules \ @@ -34,4 +30,3 @@ builder_run_action clean rm -rf ./build/ builder_run_action configure node_select_version_and_npm_ci builder_run_action build tsc --build # builder_run_action test # no tests at this time -builder_run_action publish ci_publish_npm diff --git a/core/include/ldml/package.json b/core/include/ldml/package.json index ba9acf063e..6cd3da4562 100644 --- a/core/include/ldml/package.json +++ b/core/include/ldml/package.json @@ -16,6 +16,7 @@ "scripts": {}, "repository": { "type": "git", - "url": "git+https://github.com/keymanapp/keyman.git" + "url": "git+https://github.com/keymanapp/keyman.git", + "directory": "core/include/ldml" } } diff --git a/core/src/kmx/kmx_processevent.cpp b/core/src/kmx/kmx_processevent.cpp index 921e8d9212..09ebcdd4cd 100644 --- a/core/src/kmx/kmx_processevent.cpp +++ b/core/src/kmx/kmx_processevent.cpp @@ -107,10 +107,14 @@ KMX_BOOL KMX_ProcessEvent::ProcessEvent( if (kbd->StartGroup[BEGIN_UNICODE] == (KMX_DWORD) -1) { DebugLog("Non-Unicode keyboards are not supported."); + DeleteInternalDebugItems(); + state->debug_items().push_end(m_actions.Length(), 0); m_core_state = nullptr; return FALSE; } + // TODO: what about debug_item state for all shortcut return paths below? + // TODO: this needs to be cleaned up; see #11909 switch (vkey) { case KM_CORE_VKEY_CAPS: if (KeyCapsLockPress(modifiers, isKeyDown)) diff --git a/developer/docs/help/context/index.md b/developer/docs/help/context/index.md index 04028b35c1..d7bf164c30 100644 --- a/developer/docs/help/context/index.md +++ b/developer/docs/help/context/index.md @@ -42,12 +42,6 @@ title: Context Help [kmc Command-line Options](kmc) -[kmlmc Command-line Options](kmlmc) - -[kmlmi Command-line Options](kmlmi) - -[kmlmp Command-line Options](kmlmp) - [Character Map](character-map) [Message Window](messages) diff --git a/developer/docs/help/context/kmlmc.md b/developer/docs/help/context/kmlmc.md deleted file mode 100644 index 33edf500f5..0000000000 --- a/developer/docs/help/context/kmlmc.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: kmlmc - Command Line Lexical Model Compiler (deprecated) ---- - -kmlmc has been replaced by [kmc](../reference/kmc). diff --git a/developer/docs/help/context/kmlmi.md b/developer/docs/help/context/kmlmi.md deleted file mode 100644 index dc47cbbc39..0000000000 --- a/developer/docs/help/context/kmlmi.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: kmlmi - Command Line Lexical Model model_info Compiler (deprecated) ---- - -kmlmi has been replaced by [kmc](../reference/kmc). diff --git a/developer/docs/help/context/kmlmp.md b/developer/docs/help/context/kmlmp.md deleted file mode 100644 index 3442d8f142..0000000000 --- a/developer/docs/help/context/kmlmp.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: kmlmp - Command Line Lexical Model Package Compiler (deprecated) ---- - -kmlmp has been replaced by [kmc](../reference/kmc). diff --git a/developer/docs/help/reference/kmc/cli/kmcomp-migration.md b/developer/docs/help/reference/kmc/cli/kmcomp-migration.md index c864e1bc90..e3cd9f28b7 100644 --- a/developer/docs/help/reference/kmc/cli/kmcomp-migration.md +++ b/developer/docs/help/reference/kmc/cli/kmcomp-migration.md @@ -5,9 +5,8 @@ title: Migrating from kmcomp to kmc `kmcomp` was the command-line compiler for Keyman Developer through version 16.0. Version 17.0 replaces `kmcomp` with `kmc`. -The lexical model command-line tooling, `kmlmc`, `kmlmp`, and `kmlmi`, are all -still present in version 17, but are deprecated, as the same tasks can be -performed with `kmc`. +The lexical model command-line tooling, `kmlmc`, `kmlmp`, and `kmlmi`, have +been removed in version 19.0; instead use `kmc`. ## Benefits @@ -99,21 +98,6 @@ kmcomp | kmc | notes ## Compiling a lexical model -`kmlmc` and `kmlmp` were separate tools in earlier versions of Keyman Developer, -for compiling lexical models and lexical model packages. They have both been -replaced with `kmc`. - -Old method, using kmlmc and kmlmp: - -```bash -kmlmc file.model.ts -# or specifying output filename -kmlmc -o output/path/file.model.js file.model.ts -kmlmp file.model.kps -``` - -New method, using kmc: - ```bash # recommended, build the model project: kmc build . diff --git a/developer/src/README.md b/developer/src/README.md index f3419c71dc..f9b9092448 100644 --- a/developer/src/README.md +++ b/developer/src/README.md @@ -84,7 +84,7 @@ in Keyman for Windows. ## kmc -node-based next generation compiler, hosts kmc, (and legacy kmlmc, kmlmp) +node-based next generation compiler, hosts kmc ### kmc-analyze - Analysis tools diff --git a/developer/src/build.sh b/developer/src/build.sh index fae0699748..8b57719d87 100755 --- a/developer/src/build.sh +++ b/developer/src/build.sh @@ -6,8 +6,6 @@ THIS_SCRIPT="$(readlink -f "${BASH_SOURCE[0]}")" ## END STANDARD BUILD SCRIPT INCLUDE . "$KEYMAN_ROOT/resources/build/utils.inc.sh" -. "$KEYMAN_ROOT/resources/build/ci/ci-publish.inc.sh" -. "$KEYMAN_ROOT/developer/src/packages.inc.sh" builder_describe \ "Keyman Developer" \ @@ -17,7 +15,7 @@ builder_describe \ build \ test \ "api Analyze API and prepare API documentation" \ - "publish Prepare files for distribution, publish symbols, publish or pack npm packages, and build installer" \ + "publish Prepare files for distribution, publish symbols, and build installer" \ "install Install built programs locally" \ ":common Developer common files" \ ":ext Third party components" \ @@ -42,9 +40,7 @@ builder_describe \ ":setup Keyman Developer setup bootstrap" \ ":test=test/auto Various older tests (others in each module)" \ ":tike Keyman Developer IDE" \ - ":inst Bundled installers" \ - "--npm-publish+ For publish, do a npm publish, not npm pack (only for CI)" \ - "--dry-run,-n+ Don't actually publish anything to external endpoints, just dry run" + ":inst Bundled installers" builder_describe_platform \ :ext win,delphi \ @@ -76,25 +72,6 @@ fi function do_prepublish() { builder_heading "prepublish - verify environment before build" - # - # Make sure that package*.json have not been modified before - # - - pushd "$KEYMAN_ROOT" >/dev/null - if git status --porcelain | grep -qP 'package(-lock)?\.json'; then - builder_echo "The following package.json files have been modified:" - git status --porcelain | grep -P 'package(-lock)?\.json' - builder_die "The publish action will not run until these files are checked in or reverted." - fi - popd - - # - # To ensure that we cache the top-level package.json, we must call this before - # the global publish - # - - ci_publish_cleanup - # # Verify that the Delphi environment is correct for a release build # @@ -138,44 +115,7 @@ builder_run_action api api-documenter markdown -i ../build/api -o .. #------------------------------------------------------------------------------------------------------------------- -function do_publish() { - #-------------------------------------------------------- - # TODO: Hard-coded calls to /common packages which need - # publishing; this should be able to be removed once we - # move the publish call to the top-level - - local DRY_RUN= NPM_PUBLISH= - - if builder_has_option --npm-publish; then - NPM_PUBLISH=--npm-publish - fi - - if builder_has_option --dry-run; then - DRY_RUN=--dry-run - fi - - ./common/web/utils/build.sh publish $DRY_RUN $NPM_PUBLISH - ../../common/web/keyman-version/build.sh publish $DRY_RUN $NPM_PUBLISH - ../../common/web/langtags/build.sh publish $DRY_RUN $NPM_PUBLISH - ../../common/web/types/build.sh publish $DRY_RUN $NPM_PUBLISH - ../../core/include/ldml/build.sh publish $DRY_RUN $NPM_PUBLISH - # end TODO - #-------------------------------------------------------- - - builder_echo info "Cleaning up package.json after 'npm version'" - # And then cleanup the mess - ci_publish_cleanup - # Restore all the package.json files and package-lock.json files that - # were clobbered by 'npm version' - pushd "$KEYMAN_ROOT" >/dev/null - git checkout package.json package-lock.json '**/package.json' - popd - - # TODO: Copy ../build/docs {from api action} to help.keyman.com and open PR -} - builder_run_child_actions publish -builder_run_action publish do_publish #------------------------------------------------------------------------------------------------------------------- diff --git a/developer/src/common/delphi/components/KeymanDeveloperDebuggerMemo.pas b/developer/src/common/delphi/components/KeymanDeveloperDebuggerMemo.pas index c6a703581b..54e2c87ee8 100644 --- a/developer/src/common/delphi/components/KeymanDeveloperDebuggerMemo.pas +++ b/developer/src/common/delphi/components/KeymanDeveloperDebuggerMemo.pas @@ -36,6 +36,7 @@ type TMemoSelection = record Start, Finish: Integer; Anchor: Integer; + function ToString: string; end; TKeymanDeveloperDebuggerMemo = class(TRichEdit41) @@ -107,6 +108,8 @@ end; function TKeymanDeveloperDebuggerMemo.GetSelection: TMemoSelection; begin + Result.Anchor := 0; + // EM_GETSEL doesn't tell us the anchor position, but we can figure // it out with this kludge. I am not aware of side effects from this // at this time. @@ -170,4 +173,11 @@ begin RegisterComponents('Keyman', [TKeymanDeveloperDebuggerMemo]); end; +{ TMemoSelection } + +function TMemoSelection.ToString: string; +begin + Result := Format('%d %d %d', [Start, Finish, Anchor]); +end; + end. diff --git a/developer/src/common/delphi/packages/kpsfile.pas b/developer/src/common/delphi/packages/kpsfile.pas index d92c8b9ae7..87bd7b2296 100644 --- a/developer/src/common/delphi/packages/kpsfile.pas +++ b/developer/src/common/delphi/packages/kpsfile.pas @@ -70,6 +70,7 @@ type procedure DoSaveJSON(ARoot: TJSONObject); override; procedure DoLoadIni(ini: TIniFile); override; procedure DoSaveIni(ini: TIniFile); override; + procedure Cleanup; override; public function KPSOptions: TKPSOptions; @@ -110,6 +111,15 @@ begin FStrings.Assign((Source as TKPSFile).Strings); end; +procedure TKPSFile.Cleanup; +begin + inherited; + if KPSOptions.FollowKeyboardVersion then + begin + Info.Desc[PackageInfo_Version] := ''; + end; +end; + constructor TKPSFile.Create; begin FStrings := TStringList.Create; diff --git a/developer/src/common/web/utils/build.sh b/developer/src/common/web/utils/build.sh index 0f5aacbac5..fd94a8ab66 100755 --- a/developer/src/common/web/utils/build.sh +++ b/developer/src/common/web/utils/build.sh @@ -8,7 +8,6 @@ THIS_SCRIPT="$(readlink -f "${BASH_SOURCE[0]}")" . "$KEYMAN_ROOT/resources/build/utils.inc.sh" . "$KEYMAN_ROOT/resources/build/node.inc.sh" . "$KEYMAN_ROOT/resources/build/typescript.inc.sh" -. "$KEYMAN_ROOT/resources/build/ci/ci-publish.inc.sh" builder_describe "Build Keyman Developer web utility module" \ "@/common/web/types" \ @@ -16,10 +15,7 @@ builder_describe "Build Keyman Developer web utility module" \ "configure" \ "build" \ "api analyze API and prepare API documentation (no-op for now)" \ - "test" \ - publish \ - "--npm-publish+ For publish, do a npm publish, not npm pack (only for CI)" \ - "--dry-run,-n don't actually publish, just dry run" + "test" builder_describe_outputs \ configure /node_modules \ @@ -51,5 +47,4 @@ function do_build() { builder_run_action clean rm -rf ./build/ builder_run_action configure node_select_version_and_npm_ci builder_run_action build do_build -builder_run_action test typescript_run_eslint_mocha_tests 45 -builder_run_action publish ci_publish_npm +builder_run_action test typescript_run_eslint_mocha_tests 40 diff --git a/developer/src/common/web/utils/package.json b/developer/src/common/web/utils/package.json index 089800c92f..3bf769dbad 100644 --- a/developer/src/common/web/utils/package.json +++ b/developer/src/common/web/utils/package.json @@ -43,6 +43,7 @@ }, "repository": { "type": "git", - "url": "git+https://github.com/keymanapp/keyman.git" + "url": "git+https://github.com/keymanapp/keyman.git", + "directory": "developer/src/common/web/utils" } } diff --git a/developer/src/inst/kmdev.wxs b/developer/src/inst/kmdev.wxs index c57de43d82..8b10c138c7 100644 --- a/developer/src/inst/kmdev.wxs +++ b/developer/src/inst/kmdev.wxs @@ -262,14 +262,6 @@ - - - - - - - - diff --git a/developer/src/inst/node/kmlmc.cmd b/developer/src/inst/node/kmlmc.cmd deleted file mode 100644 index be3bdf06e0..0000000000 --- a/developer/src/inst/node/kmlmc.cmd +++ /dev/null @@ -1,4 +0,0 @@ -@rem This script avoids path dependencies for node for distribution -@rem with Keyman Developer. When used on platforms other than Windows, -@rem node can be used directly with the compiler (`npm link` will setup). -@"%~dp0\node.js\node.exe" "%~dp0\kmc\kmlmc.mjs" %* diff --git a/developer/src/inst/node/kmlmp.cmd b/developer/src/inst/node/kmlmp.cmd deleted file mode 100644 index 2062ae091c..0000000000 --- a/developer/src/inst/node/kmlmp.cmd +++ /dev/null @@ -1,4 +0,0 @@ -@rem This script avoids path dependencies for node for distribution -@rem with Keyman Developer. When used on platforms other than Windows, -@rem node can be used directly with the compiler (`npm link` will setup). -@"%~dp0\node.js\node.exe" "%~dp0\kmc\kmlmp.mjs" %* diff --git a/developer/src/kmc-analyze/build.sh b/developer/src/kmc-analyze/build.sh index 152756df27..f28c822b5a 100755 --- a/developer/src/kmc-analyze/build.sh +++ b/developer/src/kmc-analyze/build.sh @@ -8,15 +8,12 @@ THIS_SCRIPT="$(readlink -f "${BASH_SOURCE[0]}")" . "$KEYMAN_ROOT/resources/build/utils.inc.sh" . "$KEYMAN_ROOT/resources/build/node.inc.sh" . "$KEYMAN_ROOT/resources/build/typescript.inc.sh" -. "$KEYMAN_ROOT/resources/build/ci/ci-publish.inc.sh" builder_describe "Keyman Developer Compiler Analysis Tools" \ "@/common/web/types" \ "@/developer/src/kmc-kmn" \ "@/developer/src/common/web/utils" \ - clean configure build api test publish \ - "--npm-publish+ For publish, do a npm publish, not npm pack (only for CI)" \ - "--dry-run,-n don't actually publish, just dry run" + clean configure build api test builder_describe_outputs \ configure /node_modules \ @@ -32,4 +29,3 @@ builder_run_action configure node_select_version_and_npm_ci builder_run_action build tsc --build builder_run_action api api-extractor run --local --verbose builder_run_action test typescript_run_eslint_mocha_tests 75 -builder_run_action publish ci_publish_npm diff --git a/developer/src/kmc-analyze/package.json b/developer/src/kmc-analyze/package.json index 496e04be05..c7e2ebabe2 100644 --- a/developer/src/kmc-analyze/package.json +++ b/developer/src/kmc-analyze/package.json @@ -43,6 +43,7 @@ }, "repository": { "type": "git", - "url": "git+https://github.com/keymanapp/keyman.git" + "url": "git+https://github.com/keymanapp/keyman.git", + "directory": "developer/src/kmc-analyze" } } diff --git a/developer/src/kmc-analyze/src/osk-character-use/index.ts b/developer/src/kmc-analyze/src/osk-character-use/index.ts index 80a0ea3e0a..7058ad6776 100644 --- a/developer/src/kmc-analyze/src/osk-character-use/index.ts +++ b/developer/src/kmc-analyze/src/osk-character-use/index.ts @@ -408,6 +408,8 @@ export class AnalyzeOskCharacterUse { /** @internal */ public unitTestEndPoints = { - loadPreviousMap: this.loadPreviousMap.bind(this) + loadPreviousMap: this.loadPreviousMap.bind(this), + addStrings: this.addStrings.bind(this), + stringToUnicodeSequence: AnalyzeOskCharacterUse.stringToUnicodeSequence }; } \ No newline at end of file diff --git a/developer/src/kmc-analyze/test/fixtures/osk-character-use/mock-map-no-counts.json b/developer/src/kmc-analyze/test/fixtures/osk-character-use/mock-map-no-counts.json new file mode 100644 index 0000000000..713091194b --- /dev/null +++ b/developer/src/kmc-analyze/test/fixtures/osk-character-use/mock-map-no-counts.json @@ -0,0 +1,10 @@ +{ + "map": [ + { + "usages": [ + "U+1780", + "U+1781" + ] + } + ] +} \ No newline at end of file diff --git a/developer/src/kmc-analyze/test/fixtures/osk-character-use/mock-map-with-counts.json b/developer/src/kmc-analyze/test/fixtures/osk-character-use/mock-map-with-counts.json new file mode 100644 index 0000000000..bec0e8727b --- /dev/null +++ b/developer/src/kmc-analyze/test/fixtures/osk-character-use/mock-map-with-counts.json @@ -0,0 +1,12 @@ +{ + "map": [ + { + "usages": [ + { + "char": "U+1780", + "count": 2 + } + ] + } + ] +} \ No newline at end of file diff --git a/developer/src/kmc-analyze/test/osk-character-use-format.tests.ts b/developer/src/kmc-analyze/test/osk-character-use-format.tests.ts new file mode 100644 index 0000000000..9acd87403f --- /dev/null +++ b/developer/src/kmc-analyze/test/osk-character-use-format.tests.ts @@ -0,0 +1,70 @@ +/* + * Keyman is copyright (C) SIL Global. MIT License. + */ +import { assert } from 'chai'; +import 'mocha'; +import { AnalyzeOskCharacterUse } from '../src/osk-character-use/index.js'; +import { TestCompilerCallbacks } from '@keymanapp/developer-test-helpers'; + +describe('AnalyzeOskCharacterUse output formats', function() { + const callbacks = new TestCompilerCallbacks(); + + const dummyStrings = { + 'a': [{ filename: 'file1.kvks', count: 1 }], + 'b': [{ filename: 'file2.kvks', count: 2 }] + }; + + this.beforeEach(function() { + callbacks.clear(); + }); + + this.afterEach(function() { + if (this.currentTest?.isFailed()) { + callbacks.printMessages(); + } + }); + + it('generates .txt format correctly', function() { + const a = new AnalyzeOskCharacterUse(callbacks, { includeCounts: true }); + a.unitTestEndPoints.addStrings(['a', 'b'], 'testfile.kvks'); + const txt = a.getStrings('.txt'); + assert.isTrue(txt.some(line => line.includes('U+'))); + assert.match(txt[0], /^U\+[A-F0-9]{4}/); + }); + + it('generates .md format correctly', function() { + const a = new AnalyzeOskCharacterUse(callbacks, { includeCounts: true }); + (a as any)._strings = dummyStrings; + const md = a.getStrings('.md'); + // test header + assert.match(md[0], /^PUA\s+\|\s+Code Points\s+\|\s+Key Caps$/); + // test data + assert.match(md[2], /^U\+[A-F0-9]{4}\s+\|\s+U\+[A-F0-9]{4}\s+\|\s+\S/); + }); + + it('generates .json format correctly', function() { + const a = new AnalyzeOskCharacterUse(callbacks, { includeCounts: true }); + (a as any)._strings = dummyStrings; + const json = a.getStrings('.json').join('\n'); + const parsed = JSON.parse(json); + assert.isArray(parsed.map); + assert.lengthOf(parsed.map, 2); + assert.equal(parsed.map[0].usages[0].filename, 'file1.kvks'); + assert.equal(parsed.map[1].usages[0].filename, 'file2.kvks'); + }); + + describe('unitTestEndPoints', function() { + it('converts BMP strings (U+0000–U+FFFF) correctly', function() { + const a = new AnalyzeOskCharacterUse(callbacks); + const seq = a.unitTestEndPoints.stringToUnicodeSequence('ab'); + assert.equal(seq, 'U+0061 U+0062'); + }); + + it('converts supplementary characters (U+10000–U+10FFFF) correctly', function() { + const a = new AnalyzeOskCharacterUse(callbacks); + // 😀 (U+1F600) and 🦊 (U+1F98A) + const seq = a.unitTestEndPoints.stringToUnicodeSequence('😀🦊'); + assert.equal(seq, 'U+1F600 U+1F98A'); + }); + }); +}); \ No newline at end of file diff --git a/developer/src/kmc-analyze/test/osk-character-use-messages.tests.ts b/developer/src/kmc-analyze/test/osk-character-use-messages.tests.ts new file mode 100644 index 0000000000..540ef3cb41 --- /dev/null +++ b/developer/src/kmc-analyze/test/osk-character-use-messages.tests.ts @@ -0,0 +1,60 @@ +/* + * Keyman is copyright (C) SIL Global. MIT License. + */ +import { assert } from 'chai'; +import 'mocha'; +import { TestCompilerCallbacks } from '@keymanapp/developer-test-helpers'; +import { AnalyzeOskCharacterUse } from '../src/osk-character-use/index.js'; +import { AnalyzerMessages } from '../src/analyzer-messages.js'; +import { makePathToFixture } from './helpers/index.js'; + +describe('AnalyzeOskCharacterUse warnings', function() { + const callbacks = new TestCompilerCallbacks(); + + const MOCK_MAP_NO_COUNTS = makePathToFixture( + 'osk-character-use', + 'mock-map-no-counts.json' + ); + const MOCK_MAP_WITH_COUNTS = makePathToFixture( + 'osk-character-use', + 'mock-map-with-counts.json' + ); + + this.beforeEach(function() { + callbacks.clear(); + }); + + this.afterEach(function() { + if (this.currentTest?.isFailed()) { + callbacks.printMessages(); + } + }); + + it('warns if previous map did not include counts but includeCounts=true', function() { + const a = new AnalyzeOskCharacterUse(callbacks, { + includeCounts: true + }); + + const result = a.unitTestEndPoints.loadPreviousMap(MOCK_MAP_NO_COUNTS); + assert.isNotNull(result, 'Expected map to be loaded successfully'); + + assert.isTrue( + callbacks.hasMessage(AnalyzerMessages.WARN_PreviousMapDidNotIncludeCounts), + 'Expected Warn_PreviousMapDidNotIncludeCounts warning' + ); + }); + + it('warns if previous map did include counts but includeCounts=false', function() { + const a = new AnalyzeOskCharacterUse(callbacks, { + includeCounts: false + }); + + const result = a.unitTestEndPoints.loadPreviousMap(MOCK_MAP_WITH_COUNTS); + assert.isNotNull(result, 'Expected map to be loaded successfully'); + + assert.isTrue( + callbacks.hasMessage(AnalyzerMessages.WARN_PreviousMapDidIncludeCounts), + 'Expected Warn_PreviousMapDidIncludeCounts warning' + ); + }); +}); diff --git a/developer/src/kmc-copy/build.sh b/developer/src/kmc-copy/build.sh index 45e9029f09..fe9ffc1086 100755 --- a/developer/src/kmc-copy/build.sh +++ b/developer/src/kmc-copy/build.sh @@ -11,16 +11,13 @@ THIS_SCRIPT="$(readlink -f "${BASH_SOURCE[0]}")" . "$KEYMAN_ROOT/resources/build/utils.inc.sh" . "$KEYMAN_ROOT/resources/build/node.inc.sh" . "$KEYMAN_ROOT/resources/build/typescript.inc.sh" -. "$KEYMAN_ROOT/resources/build/ci/ci-publish.inc.sh" builder_describe "Build Keyman kmc-copy module" \ "@/common/web/keyman-version" \ "@/common/web/types" \ "@/developer/src/common/web/test-helpers" \ "@/developer/src/common/web/utils" \ - clean configure build api test publish \ - "--npm-publish+ For publish, do a npm publish, not npm pack (only for CI)" \ - "--dry-run,-n don't actually publish, just dry run" + clean configure build api test builder_describe_outputs \ configure /node_modules \ @@ -42,5 +39,3 @@ builder_run_action api api-extractor run --local --verbose # note: `export TEST_SAVE_FIXTURES=1` to get a copy of cloud-based fixtures saved to online/ # TODO: -skip-full builder_run_action test typescript_run_eslint_mocha_tests 75 - -builder_run_action publish ci_publish_npm diff --git a/developer/src/kmc-copy/package.json b/developer/src/kmc-copy/package.json index 130ada5681..1b3f8de371 100644 --- a/developer/src/kmc-copy/package.json +++ b/developer/src/kmc-copy/package.json @@ -58,6 +58,7 @@ }, "repository": { "type": "git", - "url": "git+https://github.com/keymanapp/keyman.git" + "url": "git+https://github.com/keymanapp/keyman.git", + "directory": "developer/src/kmc-copy" } } diff --git a/developer/src/kmc-generate/build.sh b/developer/src/kmc-generate/build.sh index c02a7ed26a..d67cbaf21a 100755 --- a/developer/src/kmc-generate/build.sh +++ b/developer/src/kmc-generate/build.sh @@ -11,7 +11,6 @@ THIS_SCRIPT="$(readlink -f "${BASH_SOURCE[0]}")" . "$KEYMAN_ROOT/resources/build/utils.inc.sh" . "$KEYMAN_ROOT/resources/build/node.inc.sh" . "$KEYMAN_ROOT/resources/build/typescript.inc.sh" -. "$KEYMAN_ROOT/resources/build/ci/ci-publish.inc.sh" builder_describe "Build Keyman kmc-generate module" \ "@/common/web/keyman-version" \ @@ -19,9 +18,7 @@ builder_describe "Build Keyman kmc-generate module" \ "@/common/web/types" \ "@/developer/src/common/web/test-helpers" \ "@/developer/src/common/web/utils" \ - clean configure build api test publish \ - "--npm-publish+ For publish, do a npm publish, not npm pack (only for CI)" \ - "--dry-run,-n don't actually publish, just dry run" + clean configure build api test builder_describe_outputs \ configure /node_modules \ @@ -44,4 +41,3 @@ builder_run_action configure node_select_version_and_npm_ci builder_run_action build do_build builder_run_action api api-extractor run --local --verbose builder_run_action test typescript_run_eslint_mocha_tests -builder_run_action publish ci_publish_npm diff --git a/developer/src/kmc-generate/package.json b/developer/src/kmc-generate/package.json index da581a127e..20738b0d2a 100644 --- a/developer/src/kmc-generate/package.json +++ b/developer/src/kmc-generate/package.json @@ -59,6 +59,7 @@ }, "repository": { "type": "git", - "url": "git+https://github.com/keymanapp/keyman.git" + "url": "git+https://github.com/keymanapp/keyman.git", + "directory": "developer/src/kmc-generate" } } diff --git a/developer/src/kmc-keyboard-info/build.sh b/developer/src/kmc-keyboard-info/build.sh index 36a840212f..fe8ecfac58 100755 --- a/developer/src/kmc-keyboard-info/build.sh +++ b/developer/src/kmc-keyboard-info/build.sh @@ -18,10 +18,7 @@ builder_describe "Build Keyman kmc keyboard-info Compiler module" \ "configure" \ "build" \ "api analyze API and prepare API documentation" \ - "test" \ - "publish publish to npm" \ - "--npm-publish+ For publish, do a npm publish, not npm pack (only for CI)" \ - "--dry-run,-n don't actually publish, just dry run" + "test" builder_describe_outputs \ configure /node_modules \ @@ -39,7 +36,3 @@ builder_run_action api api-extractor run --local --verbose builder_run_action test typescript_run_eslint_mocha_tests #------------------------------------------------------------------------------------------------------------------- - -. "$KEYMAN_ROOT/resources/build/ci/ci-publish.inc.sh" - -builder_run_action publish ci_publish_npm diff --git a/developer/src/kmc-keyboard-info/package.json b/developer/src/kmc-keyboard-info/package.json index 13af66aae0..5b0c463b3a 100644 --- a/developer/src/kmc-keyboard-info/package.json +++ b/developer/src/kmc-keyboard-info/package.json @@ -43,6 +43,7 @@ }, "repository": { "type": "git", - "url": "git+https://github.com/keymanapp/keyman.git" + "url": "git+https://github.com/keymanapp/keyman.git", + "directory": "developer/src/kmc-keyboard-info" } } diff --git a/developer/src/kmc-kmn/build.sh b/developer/src/kmc-kmn/build.sh index 7d94f880df..27fb958486 100755 --- a/developer/src/kmc-kmn/build.sh +++ b/developer/src/kmc-kmn/build.sh @@ -11,7 +11,6 @@ THIS_SCRIPT="$(readlink -f "${BASH_SOURCE[0]}")" . "$KEYMAN_ROOT/resources/build/utils.inc.sh" . "$KEYMAN_ROOT/resources/build/node.inc.sh" . "$KEYMAN_ROOT/resources/build/typescript.inc.sh" -. "$KEYMAN_ROOT/resources/build/ci/ci-publish.inc.sh" builder_describe "Keyman Developer Compiler Module for .kmn to .kmx" \ "@/common/web/keyman-version" \ @@ -23,10 +22,7 @@ builder_describe "Keyman Developer Compiler Module for .kmn to .kmx" \ "build" \ "clean" \ "api analyze API and prepare API documentation" \ - "test" \ - "publish publish to npm" \ - "--npm-publish+ For publish, do a npm publish, not npm pack (only for CI)" \ - "--dry-run,-n don't actually publish, just dry run" + "test" builder_describe_outputs \ configure /node_modules \ @@ -71,7 +67,3 @@ function do_test() { builder_run_action build do_build builder_run_action api api-extractor run --local --verbose builder_run_action test do_test - -#------------------------------------------------------------------------------------------------------------------- - -builder_run_action publish ci_publish_npm diff --git a/developer/src/kmc-kmn/package.json b/developer/src/kmc-kmn/package.json index 34e076b5c0..f9c82fb4e9 100644 --- a/developer/src/kmc-kmn/package.json +++ b/developer/src/kmc-kmn/package.json @@ -61,6 +61,7 @@ }, "repository": { "type": "git", - "url": "git+https://github.com/keymanapp/keyman.git" + "url": "git+https://github.com/keymanapp/keyman.git", + "directory": "developer/src/kmc-kmn" } } diff --git a/developer/src/kmc-ldml/build.sh b/developer/src/kmc-ldml/build.sh index 2f3eb01bc2..708a4c9b3d 100755 --- a/developer/src/kmc-ldml/build.sh +++ b/developer/src/kmc-ldml/build.sh @@ -23,10 +23,7 @@ builder_describe "Keyman kmc Keyboard Compiler module" \ "api analyze API and prepare API documentation" \ "clean" \ "test" \ - "build-fixtures builds test fixtures for manual examination" \ - "publish publish to npm" \ - "--npm-publish+ For publish, do a npm publish, not npm pack (only for CI)" \ - "--dry-run,-n don't actually publish, just dry run" + "build-fixtures builds test fixtures for manual examination" builder_describe_outputs \ configure /developer/src/kmc-ldml/src/util/abnf/46/transform-from-required.js \ @@ -90,9 +87,3 @@ builder_run_action build do_build builder_run_action build-fixtures do_build_fixtures builder_run_action api api-extractor run --local --verbose builder_run_action test typescript_run_eslint_mocha_tests 90 - -#------------------------------------------------------------------------------------------------------------------- - -. "$KEYMAN_ROOT/resources/build/ci/ci-publish.inc.sh" - -builder_run_action publish ci_publish_npm diff --git a/developer/src/kmc-ldml/package.json b/developer/src/kmc-ldml/package.json index ce0a83e18e..9e2a1c6831 100644 --- a/developer/src/kmc-ldml/package.json +++ b/developer/src/kmc-ldml/package.json @@ -65,6 +65,7 @@ }, "repository": { "type": "git", - "url": "git+https://github.com/keymanapp/keyman.git" + "url": "git+https://github.com/keymanapp/keyman.git", + "directory": "developer/src/kmc-ldml" } } diff --git a/developer/src/kmc-model-info/build.sh b/developer/src/kmc-model-info/build.sh index 00983ae6ea..fb4743700f 100755 --- a/developer/src/kmc-model-info/build.sh +++ b/developer/src/kmc-model-info/build.sh @@ -15,10 +15,7 @@ builder_describe "Build Keyman kmc Lexical Model model-info Compiler module" \ "configure" \ "build" \ "api analyze API and prepare API documentation" \ - "test" \ - "publish publish to npm" \ - "--npm-publish+ For publish, do a npm publish, not npm pack (only for CI)" \ - "--dry-run,-n don't actually publish, just dry run" + "test" builder_describe_outputs \ configure /node_modules \ @@ -34,9 +31,3 @@ builder_run_action configure node_select_version_and_npm_ci builder_run_action build tsc --build builder_run_action api api-extractor run --local --verbose builder_run_action test typescript_run_eslint_mocha_tests 55 - -#------------------------------------------------------------------------------------------------------------------- - -. "$KEYMAN_ROOT/resources/build/ci/ci-publish.inc.sh" - -builder_run_action publish ci_publish_npm diff --git a/developer/src/kmc-model-info/package.json b/developer/src/kmc-model-info/package.json index 4c715ccf6f..c747a922c4 100644 --- a/developer/src/kmc-model-info/package.json +++ b/developer/src/kmc-model-info/package.json @@ -48,6 +48,7 @@ }, "repository": { "type": "git", - "url": "git+https://github.com/keymanapp/keyman.git" + "url": "git+https://github.com/keymanapp/keyman.git", + "directory": "developer/src/kmc-model-info" } } diff --git a/developer/src/kmc-model/build.sh b/developer/src/kmc-model/build.sh index bd758b18f9..4b5f15cc30 100755 --- a/developer/src/kmc-model/build.sh +++ b/developer/src/kmc-model/build.sh @@ -8,7 +8,6 @@ THIS_SCRIPT="$(readlink -f "${BASH_SOURCE[0]}")" . "$KEYMAN_ROOT/resources/build/utils.inc.sh" . "$KEYMAN_ROOT/resources/build/node.inc.sh" . "$KEYMAN_ROOT/resources/build/typescript.inc.sh" -. "$KEYMAN_ROOT/resources/build/ci/ci-publish.inc.sh" builder_describe "Keyman kmc Lexical Model Compiler module" \ "@/common/web/keyman-version" \ @@ -18,10 +17,7 @@ builder_describe "Keyman kmc Lexical Model Compiler module" \ "configure" \ "build" \ "api analyze API and prepare API documentation" \ - "test" \ - "publish publish to npm" \ - "--npm-publish+ For publish, do a npm publish, not npm pack (only for CI)" \ - "--dry-run,-n don't actually publish, just dry run" + "test" builder_describe_outputs \ configure /node_modules \ @@ -42,5 +38,3 @@ builder_run_action configure node_select_version_and_npm_ci builder_run_action build do_build builder_run_action api api-extractor run --local --verbose builder_run_action test typescript_run_eslint_mocha_tests -builder_run_action publish ci_publish_npm - diff --git a/developer/src/kmc-model/package.json b/developer/src/kmc-model/package.json index 8dff9fef1e..481822e686 100644 --- a/developer/src/kmc-model/package.json +++ b/developer/src/kmc-model/package.json @@ -63,6 +63,7 @@ }, "repository": { "type": "git", - "url": "git+https://github.com/keymanapp/keyman.git" + "url": "git+https://github.com/keymanapp/keyman.git", + "directory": "developer/src/kmc-model" } } diff --git a/developer/src/kmc-package/build.sh b/developer/src/kmc-package/build.sh index 66f430ceb4..f1d6ba8dcc 100755 --- a/developer/src/kmc-package/build.sh +++ b/developer/src/kmc-package/build.sh @@ -11,7 +11,6 @@ THIS_SCRIPT="$(readlink -f "${BASH_SOURCE[0]}")" . "$KEYMAN_ROOT/resources/build/utils.inc.sh" . "$KEYMAN_ROOT/resources/build/node.inc.sh" . "$KEYMAN_ROOT/resources/build/typescript.inc.sh" -. "$KEYMAN_ROOT/resources/build/ci/ci-publish.inc.sh" builder_describe "Build Keyman kmc Package Compiler module" \ "@/common/web/keyman-version" \ @@ -21,10 +20,8 @@ builder_describe "Build Keyman kmc Package Compiler module" \ "build" \ "api analyze API and prepare API documentation" \ "clean" \ - "test" \ - "publish publish to npm" \ - "--npm-publish+ For publish, do a npm publish, not npm pack (only for CI)" \ - "--dry-run,-n don't actually publish, just dry run" + "test" + builder_describe_outputs \ configure /node_modules \ build /developer/src/kmc-package/build/src/main.js \ @@ -39,4 +36,3 @@ builder_run_action configure node_select_version_and_npm_ci builder_run_action build tsc --build builder_run_action api api-extractor run --local --verbose builder_run_action test typescript_run_eslint_mocha_tests -builder_run_action publish ci_publish_npm diff --git a/developer/src/kmc-package/package.json b/developer/src/kmc-package/package.json index 5e2df84fc6..edfba42073 100644 --- a/developer/src/kmc-package/package.json +++ b/developer/src/kmc-package/package.json @@ -61,6 +61,7 @@ }, "repository": { "type": "git", - "url": "git+https://github.com/keymanapp/keyman.git" + "url": "git+https://github.com/keymanapp/keyman.git", + "directory": "developer/src/kmc-package" } } diff --git a/developer/src/kmc-package/src/compiler/kmp-inf-writer.ts b/developer/src/kmc-package/src/compiler/kmp-inf-writer.ts index d7b6f8bab6..2c71035ae8 100644 --- a/developer/src/kmc-package/src/compiler/kmp-inf-writer.ts +++ b/developer/src/kmc-package/src/compiler/kmp-inf-writer.ts @@ -138,7 +138,7 @@ export class KmpInfWriter { private saveKeyboards() { // keyboards - for(let i = 0; i < this.data.keyboards?.length ?? 0; i++) { + for(let i = 0; i < (this.data.keyboards?.length ?? 0); i++) { const keyboard = this.data.keyboards[i]; this.addSection('Keyboard'+i.toString()); this.addString('Name', keyboard.name); @@ -154,7 +154,7 @@ export class KmpInfWriter { this.addString('DisplayFont', keyboard.displayFont); } - for(let j = 0; j < keyboard.languages?.length ?? 0; j++) { + for(let j = 0; j < (keyboard.languages?.length ?? 0); j++) { const language = keyboard.languages[j]; this.addString('Language'+j.toString(), language.id+','+language.name); } diff --git a/developer/src/kmc/README.md b/developer/src/kmc/README.md index 2ab17f67e7..0490998e4d 100644 --- a/developer/src/kmc/README.md +++ b/developer/src/kmc/README.md @@ -175,14 +175,6 @@ The temp_path must be a path outside the repository to avoid npm getting confused by the root package.json. This is called by inst/download.in.mak normally when building the Keyman Developer installer. -## Publishing to NPM - -```shell -./build.sh publish [--dry-run] -``` - -Publishes the current release to NPM. This should only be run from CI. - [kmc]: https://help.keyman.com/developer/current-version/reference/kmc/cli [file-layout]: https://help.keyman.com/developer/current-version/reference/file-layout diff --git a/developer/src/kmc/build-bundler.js b/developer/src/kmc/build-bundler.js index 9b5f9cdd9b..1cfbe2568f 100644 --- a/developer/src/kmc/build-bundler.js +++ b/developer/src/kmc/build-bundler.js @@ -7,8 +7,6 @@ import esbuild from 'esbuild'; await esbuild.build({ entryPoints: [ 'build/src/kmc.js', - 'build/src/kmlmc.js', - 'build/src/kmlmp.js', ], bundle: true, format: 'esm', diff --git a/developer/src/kmc/build.sh b/developer/src/kmc/build.sh index e784a441cc..81cc94dcca 100755 --- a/developer/src/kmc/build.sh +++ b/developer/src/kmc/build.sh @@ -8,11 +8,10 @@ THIS_SCRIPT="$(readlink -f "${BASH_SOURCE[0]}")" . "${THIS_SCRIPT%/*}/../../../resources/build/builder-full.inc.sh" ## END STANDARD BUILD SCRIPT INCLUDE -. "$KEYMAN_ROOT/resources/build/ci/ci-publish.inc.sh" . "$KEYMAN_ROOT/resources/build/utils.inc.sh" . "$KEYMAN_ROOT/resources/build/node.inc.sh" . "$KEYMAN_ROOT/resources/build/typescript.inc.sh" -. "$KEYMAN_ROOT/developer/src/packages.inc.sh" +. "$KEYMAN_ROOT/resources/build/ci/npm-packages.inc.sh" builder_describe "Build Keyman Keyboard Compiler kmc" \ "@/common/include" \ @@ -35,10 +34,7 @@ builder_describe "Build Keyman Keyboard Compiler kmc" \ "bundle creates a bundled version of kmc" \ "api prepare compiler error documentation" \ "test run automated tests for kmc" \ - publish \ - "--build-path=BUILD_PATH build directory for bundle" \ - "--npm-publish+ For publish, do a npm publish, not npm pack (only for CI)" \ - "--dry-run,-n don't actually publish, just dry run" + "--build-path=BUILD_PATH build directory for bundle" builder_describe_outputs \ configure /node_modules \ @@ -114,4 +110,3 @@ builder_run_action build do_build builder_run_action test do_test builder_run_action api do_api builder_run_action bundle do_bundle -builder_run_action publish ci_publish_npm diff --git a/developer/src/kmc/package.json b/developer/src/kmc/package.json index 91d6cdd53b..39d839bc84 100644 --- a/developer/src/kmc/package.json +++ b/developer/src/kmc/package.json @@ -11,10 +11,8 @@ ], "scripts": { "build": "tsc -b", - "bundle": "npm run bundle-kmc && npm run bundle-kmlmc && npm run bundle-kmlmp", + "bundle": "npm run bundle-kmc", "bundle-kmc": "esbuild build/src/kmc.js --bundle --platform=node --target=es2022 > build/cjs-src/kmc.cjs", - "bundle-kmlmc": "esbuild build/src/kmlmc.js --bundle --platform=node --target=es2022 > build/cjs-src/kmlmc.cjs", - "bundle-kmlmp": "esbuild build/src/kmlmp.js --bundle --platform=node --target=es2022 > build/cjs-src/kmlmp.cjs", "test": "eslint . && cd test && tsc -b && cd .. && mocha" }, "type": "module", @@ -29,9 +27,7 @@ }, "main": "build/src/kmc.js", "bin": { - "kmc": "build/src/kmc.js", - "kmlmc": "build/src/kmlmc.js", - "kmlmp": "build/src/kmlmp.js" + "kmc": "build/src/kmc.js" }, "dependencies": { "@keymanapp/common-types": "*", @@ -81,6 +77,7 @@ }, "repository": { "type": "git", - "url": "git+https://github.com/keymanapp/keyman.git" + "url": "git+https://github.com/keymanapp/keyman.git", + "directory": "developer/src/kmc" } } diff --git a/developer/src/kmc/src/kmlmc.ts b/developer/src/kmc/src/kmlmc.ts deleted file mode 100644 index ca2fd4d6b0..0000000000 --- a/developer/src/kmc/src/kmlmc.ts +++ /dev/null @@ -1,67 +0,0 @@ -#!/usr/bin/env node -/** - * kmlmc - Keyman Lexical Model Compiler - */ - -import { Command } from 'commander'; -import { LexicalModelCompiler } from '@keymanapp/kmc-model'; -import { SysExits } from './util/sysexits.js'; -import KEYMAN_VERSION from "@keymanapp/keyman-version"; -import { NodeCompilerCallbacks } from './util/NodeCompilerCallbacks.js'; - -let inputFilename: string; -const program = new Command(); - -/* Arguments */ -program - .description('Compiles Keyman lexical models') - .version(KEYMAN_VERSION.VERSION_WITH_TAG) - .arguments('') - .action(infile => inputFilename = infile) - .option('-o, --outFile ', 'where to save the resultant file'); - -program.parse(process.argv); - -// Deal with input arguments: -if (!inputFilename) { - exitDueToUsageError('Must provide a lexical model source file.'); -} - -const callbacks = new NodeCompilerCallbacks({logLevel: 'info'}); - -const compiler = new LexicalModelCompiler(); -if(!await compiler.init(callbacks, null)) { - console.error('Initialization failed.'); - process.exit(SysExits.EX_DATAERR); -} - -let code = null; -// Compile: -try { - code = await compiler.run(inputFilename, program.opts().outFile); -} catch(e) { - console.error(e); - process.exit(SysExits.EX_DATAERR); -} - -if(!code) { - console.error('Compilation failed.') - process.exit(SysExits.EX_DATAERR); -} - -// Output: -if (program.opts().outFile) { - compiler.write(code.artifacts); -} else { - // TODO(lowpri): if writing to console then log messages should all be to stderr? - const decoder = new TextDecoder(); - const text = decoder.decode(code.artifacts.js.data); - console.log(text); -} - -function exitDueToUsageError(message: string): never { - console.error(`${program.name()}: ${message}`); - console.error(); - program.outputHelp(); - return process.exit(SysExits.EX_USAGE); -} \ No newline at end of file diff --git a/developer/src/kmc/src/kmlmp.ts b/developer/src/kmc/src/kmlmp.ts deleted file mode 100644 index d5fdb20c16..0000000000 --- a/developer/src/kmc/src/kmlmp.ts +++ /dev/null @@ -1,60 +0,0 @@ -#!/usr/bin/env node -/** - * kmlmp - Keyman Lexical Model Package Compiler - */ - -// Note: this is a deprecated package and will be removed in Keyman 19.0 - -import { Command } from 'commander'; -import { KmpCompiler } from '@keymanapp/kmc-package'; -import { SysExits } from './util/sysexits.js'; -import KEYMAN_VERSION from "@keymanapp/keyman-version"; -import { NodeCompilerCallbacks } from './util/NodeCompilerCallbacks.js'; - -let inputFilename: string; -const program = new Command(); - -/* Arguments */ -program - .description('Compiles Keyman lexical model packages\nDeprecated: use instead; will be removed in v18') - .version(KEYMAN_VERSION.VERSION_WITH_TAG) - .arguments('') - .action(infile => inputFilename = infile) - .option('-o, --outFile ', 'where to save the resultant file'); - -program.parse(process.argv); - -// Deal with input arguments: - -if (!inputFilename) { - exitDueToUsageError('Must provide a lexical model package source file.'); -} - -const outputFilename: string = program.opts().outFile ? program.opts().outFile : inputFilename.replace(/\.kps$/, ".kmp"); - -// -// Run the compiler -// - -const callbacks = new NodeCompilerCallbacks({logLevel: 'info'}); -const kmpCompiler = new KmpCompiler(); -if(!await kmpCompiler.init(callbacks, null)) { - process.exit(1); -} - -const result = await kmpCompiler.run(inputFilename, outputFilename); -if(!result) { - process.exit(1); -} - -if(!await kmpCompiler.write(result.artifacts)) { - console.error('Failed to write kmp file'); - process.exit(1); -} - -function exitDueToUsageError(message: string): never { - console.error(`${program.name()}: ${message}`); - console.error(); - program.outputHelp(); - return process.exit(SysExits.EX_USAGE); -} diff --git a/developer/src/kmc/test/getLastGitCommitDate.tests.ts b/developer/src/kmc/test/getLastGitCommitDate.tests.ts index 2aa88aa5fa..066d986f63 100644 --- a/developer/src/kmc/test/getLastGitCommitDate.tests.ts +++ b/developer/src/kmc/test/getLastGitCommitDate.tests.ts @@ -1,3 +1,4 @@ +import { execFileSync } from 'node:child_process'; import { assert } from 'chai'; import 'mocha'; import { makePathToFixture } from './helpers/index.js'; @@ -17,8 +18,29 @@ describe('getLastGitCommitDate', function () { assert.isNull(date); }); + function isShallowRepository() { + try { + const result = execFileSync('git', ['rev-parse', '--is-shallow-repository'], { + encoding: 'utf-8', // force a string result rather than Buffer + windowsHide: true, // on windows, we may need this to suppress a console window popup + stdio: ['pipe', 'pipe', 'pipe'] // all output via pipe, so we don't get git errors on console + }); + return result.trim() == 'true'; + } catch (e) { + return false; + } + } + it('should return a valid date for a specific file in the repo', async function() { this.timeout(5000); // getLastGitCommitDate depends on git which can sometimes take longer + + if(isShallowRepository()) { + // If we have a shallow clone, then the date will be the most recent + // commit date, and we'll just skip this test. For example, this happens + // on GHA checkouts by default with actions/checkout depth=1 + this.skip(); + } + const path = makePathToFixture('get-last-git-commit-date/README.md'); const date = getLastGitCommitDate(path); // The expected date was manually extracted using the following command, with msec appended: diff --git a/developer/src/tike/build.sh b/developer/src/tike/build.sh index b9e5349f3e..15e2add3c4 100755 --- a/developer/src/tike/build.sh +++ b/developer/src/tike/build.sh @@ -72,8 +72,6 @@ function do_build() { tds2dbg "$WIN32_TARGET" cp "$WIN32_TARGET" "$DEVELOPER_PROGRAM" - cp kmlmc.cmd "$DEVELOPER_PROGRAM" - cp kmlmp.cmd "$DEVELOPER_PROGRAM" cp kmc.cmd "$DEVELOPER_PROGRAM" cp "$KEYMAN_ROOT/core/build/x86/$TARGET_PATH/src/$KEYMANCORE_DLL" "$DEVELOPER_PROGRAM" builder_if_release_build_level cp "$WIN32_TARGET_PATH/tike.dbg" "$DEVELOPER_DEBUGPATH" diff --git a/developer/src/tike/child/UfrmDebug.pas b/developer/src/tike/child/UfrmDebug.pas index 15a5b858b7..6137cab712 100644 --- a/developer/src/tike/child/UfrmDebug.pas +++ b/developer/src/tike/child/UfrmDebug.pas @@ -109,7 +109,7 @@ type procedure ResetEvents; procedure ExecuteEvent(n: Integer); - procedure ExecuteEventAction(n: Integer); + procedure ExecuteEventAction(EventNumber: Integer); procedure ExecuteEventRule(n: Integer); procedure SetExecutionPointLine(ALine: Integer); procedure SetUIStatus(const Value: TDebugUIStatus); @@ -210,6 +210,7 @@ uses dmActionsMain, Glossary, Keyman.Developer.System.Project.ProjectLog, + Keyman.System.KeymanSentryClient, Keyman.UI.Debug.CharacterGridRenderer, KeyNames, kmxfile, @@ -462,6 +463,10 @@ begin modifier := modifier and not KM_CORE_MODIFIER_LCTRL; end; + TKeymanSentryClient.Instance.Breadcrumb('default', + Format('ProcessKeyEvent: vk=%x mod=%x scan=%x beforeText="%s" beforeSelection=%s',[vkey, modifier, scan, Copy(memo.GetTextCR, 1, 256), memo.Selection.ToString]), + 'debugger'); + if not SetKeyEventContext then Exit(False); @@ -598,8 +603,14 @@ end; procedure TfrmDebug.ExecuteEvent(n: Integer); begin + TKeymanSentryClient.Instance.Breadcrumb('default', + Format('ExecuteEvent(%d/%d): [%s]; b:%s; s:%s', + [n, FEvents.Count, FEvents[n].ToString, memo.Selection.ToString, FSavedSelection.ToString]), + 'debugger'); + memo.ReadOnly := False; memo.Selection := FSavedSelection; + if FEvents[n].EventType = etAction then ExecuteEventAction(n) else ExecuteEventRule(n); @@ -667,7 +678,7 @@ begin end; -procedure TfrmDebug.ExecuteEventAction(n: Integer); +procedure TfrmDebug.ExecuteEventAction(EventNumber: Integer); type TMemoSelectionState = record Selection: TMemoSelection; @@ -711,24 +722,25 @@ procedure TfrmDebug.ExecuteEventAction(n: Integer); procedure DoBackspace(BackspaceType: km_core_backspace_type; ExpectedValue: NativeUInt); var t: string; - m, n: Integer; + m, m1: Integer; dk: TDeadKeyInfo; state: TMemoSelectionState; function AssertionMessage: string; begin Result := 'Assertion failed. Extra data: '+ + 'EventNumber='+IntToStr(EventNumber)+'; '+ 'BackspaceType='+IntToStr(Ord(BackspaceType))+'; '+ 'ExpectedValue=U+'+IntToHex(ExpectedValue, 4)+'; '+ 'memo.SelStart='+IntToStr(memo.SelStart)+'; '+ 'memo.SelLength='+IntToStr(memo.SelLength)+'; '+ - 'memo.Text='+Copy(memo.GetTextCR, 1, 256); + 'memo.Text="'+Copy(memo.GetTextCR, 1, 256)+'"'; end; begin // Offset is zero-based, but string is 1-based. Beware! state := SaveMemoSelectionState; - n := memo.SelStart; - m := n; + m1 := memo.SelStart; + m := m1; if memo.SelLength > 0 then begin @@ -800,7 +812,7 @@ procedure TfrmDebug.ExecuteEventAction(n: Integer); memo.Lines.BeginUpdate; try - memo.Text := Copy(t, 1, m) + Copy(t, n+1, MaxInt); + memo.Text := Copy(t, 1, m) + Copy(t, m1+1, MaxInt); memo.SelStart := m; finally memo.Lines.EndUpdate; @@ -894,7 +906,7 @@ procedure TfrmDebug.ExecuteEventAction(n: Integer); begin DisableUI; frmDebugStatus.Elements.UpdateStores(nil); - with FEvents[n].Action do + with FEvents[EventNumber].Action do begin case ActionType of KM_CORE_IT_EMIT_KEYSTROKE: DoEmitKeystroke(dwData); diff --git a/developer/src/tike/child/UfrmPackageEditor.pas b/developer/src/tike/child/UfrmPackageEditor.pas index f3dcc71f09..5beb0c6d77 100644 --- a/developer/src/tike/child/UfrmPackageEditor.pas +++ b/developer/src/tike/child/UfrmPackageEditor.pas @@ -635,21 +635,21 @@ end; procedure TfrmPackageEditor.editInfoNameChange(Sender: TObject); begin if FSetup > 0 then Exit; - pack.Info.Desc['Name'] := Trim(editInfoName.Text); + pack.Info.Desc[PackageInfo_Name] := Trim(editInfoName.Text); Modified := True; end; procedure TfrmPackageEditor.editInfoVersionChange(Sender: TObject); begin if FSetup > 0 then Exit; - pack.Info.Desc['Version'] := Trim(editInfoVersion.Text); + pack.Info.Desc[PackageInfo_Version] := Trim(editInfoVersion.Text); Modified := True; end; procedure TfrmPackageEditor.editInfoCopyrightChange(Sender: TObject); begin if FSetup > 0 then Exit; - pack.Info.Desc['Copyright'] := Trim(editInfoCopyright.Text); + pack.Info.Desc[PackageInfo_Copyright] := Trim(editInfoCopyright.Text); Modified := True; end; @@ -663,7 +663,7 @@ end; procedure TfrmPackageEditor.editInfoAuthorChange(Sender: TObject); begin if FSetup > 0 then Exit; - pack.Info.Desc['Author'] := Trim(editInfoAuthor.Text); + pack.Info.Desc[PackageInfo_Author] := Trim(editInfoAuthor.Text); Modified := True; end; @@ -671,16 +671,16 @@ procedure TfrmPackageEditor.editInfoEmailChange(Sender: TObject); begin if FSetup > 0 then Exit; if Trim(editInfoEmail.Text) = '' - then pack.Info.URL['Author'] := '' - else pack.Info.URL['Author'] := 'mailto:'+Trim(editInfoEmail.Text); + then pack.Info.URL[PackageInfo_Author] := '' + else pack.Info.URL[PackageInfo_Author] := 'mailto:'+Trim(editInfoEmail.Text); Modified := True; end; procedure TfrmPackageEditor.editInfoWebSiteChange(Sender: TObject); begin if FSetup > 0 then Exit; - pack.Info.Desc['WebSite'] := Trim(editInfoWebSite.Text); - pack.Info.URL['WebSite'] := Trim(editInfoWebSite.Text); + pack.Info.Desc[PackageInfo_WebSite] := Trim(editInfoWebSite.Text); + pack.Info.URL[PackageInfo_WebSite] := Trim(editInfoWebSite.Text); Modified := True; end; @@ -734,7 +734,7 @@ begin try f.Description := 'Keyboard '+ki.KeyboardName; // Fill in some info stuff as well... - if pack.Info.Desc[PackageInfo_Version] = '' then // I4690 + if not pack.KPSOptions.FollowKeyboardVersion and (pack.Info.Desc[PackageInfo_Version] = '') then // I4690 begin pack.Info.Desc[PackageInfo_Version] := ki.KeyboardVersion; end; @@ -1021,6 +1021,11 @@ procedure TfrmPackageEditor.chkFollowKeyboardVersionClick(Sender: TObject); begin if FSetup > 0 then Exit; pack.KPSOptions.FollowKeyboardVersion := chkFollowKeyboardVersion.Checked; + if chkFollowKeyboardVersion.Checked then + begin + editInfoVersion.Text := ''; + pack.Info.Desc[PackageInfo_Version] := ''; + end; EnableDetailsTabControls; Modified := True; end; @@ -1082,7 +1087,7 @@ end; procedure TfrmPackageEditor.memoInfoDescriptionChange(Sender: TObject); begin if FSetup > 0 then Exit; - pack.Info.Desc['Description'] := Trim(memoInfoDescription.Text); + pack.Info.Desc[PackageInfo_Description] := Trim(memoInfoDescription.Text); Modified := True; end; diff --git a/developer/src/tike/debug/Keyman.System.Debug.DebugEvent.pas b/developer/src/tike/debug/Keyman.System.Debug.DebugEvent.pas index a5853faba0..8b9875f7b0 100644 --- a/developer/src/tike/debug/Keyman.System.Debug.DebugEvent.pas +++ b/developer/src/tike/debug/Keyman.System.Debug.DebugEvent.pas @@ -62,6 +62,7 @@ type public constructor Create; destructor Destroy; override; + function ToString: string; override; property Action: TDebugEventActionData read FAction; property Rule: TDebugEventRuleData read FRule; property EventType: TDebugEventType read FEventType write SetEventType; @@ -94,6 +95,8 @@ type vk: uint16_t; modifier_state: uint16_t ): Boolean; overload; + + function ToString: string; override; end; implementation @@ -134,6 +137,23 @@ begin end; end; +function TDebugEvent.ToString: string; +begin + // Debug string + if FEventType = etAction then + begin + Result := Format('A %d %d %d "%s"', [Ord(FAction.ActionType), FAction.dwData, FAction.nExpectedValue, FAction.Text]); + end + else if FEventType = etRuleMatch then + begin + Result := Format('R %d %x %x %d "%s"', [FRule.ItemType, FRule.Key.VirtualKey, FRule.Key.Modifiers, FRule.Line, FRule.Context]); + end + else + begin + Result := '?'+IntToStr(Ord(FEventType)); + end; +end; + function TDebugEventList.AddActionItem(key: Word; action: pkm_core_action_item): Boolean; begin Result := True; @@ -330,6 +350,15 @@ begin end; end; +function TDebugEventList.ToString: string; +var + I: Integer; +begin + Result := ''; + for I := 0 to Count - 1 do + Result := Result + '['+IntToStr(I)+': '+Items[I].ToString + '] '; +end; + function TDebugEventList.AddStateItems( state: pkm_core_state; vk: uint16_t; @@ -342,8 +371,18 @@ var action_index: Integer; begin Result := True; + + if not Assigned(state) then + raise Exception.Create('TDebugEventList.AddStateItems: expected state not to be nil'); + debug := km_core_state_debug_items(state, nil); + if not Assigned(debug) then + raise Exception.Create('TDebugEventList.AddStateItems: expected debug not to be nil'); + action := km_core_state_action_items(state, nil); + if not Assigned(action) then + raise Exception.Create('TDebugEventList.AddStateItems: expected action not to be nil'); + action_index := 0; while debug._type <> KM_CORE_DEBUG_END do begin diff --git a/developer/src/tike/http/Keyman.Developer.System.HttpServer.AppSource.pas b/developer/src/tike/http/Keyman.Developer.System.HttpServer.AppSource.pas index 2260b8a183..904d389a08 100644 --- a/developer/src/tike/http/Keyman.Developer.System.HttpServer.AppSource.pas +++ b/developer/src/tike/http/Keyman.Developer.System.HttpServer.AppSource.pas @@ -56,6 +56,7 @@ uses Xml.XMLDoc, Xml.XMLIntf, + Keyman.System.KeymanSentryClient, RedistFiles; { TAppSourceHttpResponder } @@ -145,6 +146,7 @@ begin begin AResponseInfo.ContentType := 'application/json'; AResponseInfo.Charset := 'UTF-8'; + TKeymanSentryClient.Breadcrumb('default', Format('RespondTouchEditorState: Filename=%s[#state]', [AFilename]), 'AppSourceHttpResponder'); if TryGetSource(AFilename + '#state', FData) then AResponseInfo.ContentText := FData else AResponseInfo.ContentText := '{}'; @@ -167,6 +169,7 @@ var FData: string; begin // TODO: data will be passed separate call from touch editor later + TKeymanSentryClient.Breadcrumb('default', Format('RespondTouchEditor: Filename=%s', [AFilename]), 'AppSourceHttpResponder'); if not TryGetSource(AFilename, FData) then begin Respond404(AContext, ARequestInfo, AResponseInfo); @@ -216,6 +219,8 @@ var begin T := FSources.LockList; try + TKeymanSentryClient.Breadcrumb('default', Format('TrySetSource: Filename=%s count=%d', [Filename, T.Count]), 'AppSourceHttpResponder'); + for i := 0 to T.Count - 1 do if T[i].Filename = Filename then begin @@ -236,6 +241,7 @@ procedure TAppSourceHttpResponder.RespondGet(const AFilename: string; var FData: string; begin + TKeymanSentryClient.Breadcrumb('default', Format('RespondGet: Filename=%s', [AFilename]), 'AppSourceHttpResponder'); if TryGetSource(AFilename, FData) then begin AResponseInfo.ContentType := 'application/json'; @@ -267,6 +273,7 @@ var begin T := FSources.LockList; try + TKeymanSentryClient.Breadcrumb('default', Format('TryGetSource: Filename=%s count=%d', [Filename, T.Count]), 'AppSourceHttpResponder'); for i := 0 to T.Count - 1 do if T[i].Filename = Filename then begin @@ -281,6 +288,7 @@ end; function TAppSourceHttpResponder.GetSource(const Filename: string): string; begin + TKeymanSentryClient.Breadcrumb('default', Format('GetSource: Filename=%s', [Filename]), 'AppSourceHttpResponder'); Assert(TryGetSource(Filename, Result), 'TAppSourceHttpResponder.GetSource was asked for a file that was not registered: '+Filename); end; @@ -289,6 +297,7 @@ function TAppSourceHttpResponder.IsSourceRegistered(const Filename: string): Boo var Data: string; begin + TKeymanSentryClient.Breadcrumb('default', Format('IsSourceRegistered: Filename=%s', [Filename]), 'AppSourceHttpResponder'); Result := TryGetSource(Filename, Data); end; @@ -300,6 +309,8 @@ var begin T := FSources.LockList; try + TKeymanSentryClient.Breadcrumb('default', Format('RegisterSource: Filename=%s Update=%s count=%d', [Filename, BoolToStr(Update,True), T.Count]), 'AppSourceHttpResponder'); + S.Filename := Filename; S.Data := Data; @@ -326,6 +337,7 @@ var begin T := FSources.LockList; try + TKeymanSentryClient.Breadcrumb('default', Format('UnregisterSource: Filename=%s count=%d', [Filename, T.Count]), 'AppSourceHttpResponder'); for i := 0 to T.Count - 1 do if T[i].Filename = Filename then begin diff --git a/developer/src/tike/kmlmc.cmd b/developer/src/tike/kmlmc.cmd deleted file mode 100644 index 4f86f2e3bd..0000000000 --- a/developer/src/tike/kmlmc.cmd +++ /dev/null @@ -1,20 +0,0 @@ -@echo off -setlocal -rem This script is based on /developer/src/node/inst/kmlmc.cmd. It is stored here -rem in order to allow TIKE to call out to the compiler while debugging. -if exist "%~dp0..\inst\node\dist\node.exe" ( - rem If running in developer/src/tike/: - set nodeexe="%~dp0..\inst\node\dist\node.exe" - set nodecli="%~dp0..\kmc\build\src\kmlmc.js" -) else if exist "%~dp0..\src\inst\node\dist\node.exe" ( - rem If running in developer/bin/: - set nodeexe="%~dp0..\src\inst\node\dist\node.exe" - set nodecli="%~dp0..\src\kmc\build\src\kmlmc.js" -) else ( - rem Cannot find node or kmlmc.js relative to execution path - echo Error: node.exe or kmlmc.js not found. - exit /b 1 -) - -%nodeexe% --enable-source-maps %nodecli% %* -exit /b %errorlevel% diff --git a/developer/src/tike/kmlmp.cmd b/developer/src/tike/kmlmp.cmd deleted file mode 100644 index 716a5bf940..0000000000 --- a/developer/src/tike/kmlmp.cmd +++ /dev/null @@ -1,20 +0,0 @@ -@echo off -setlocal -rem This script is based on /developer/src/node/inst/kmlmp.cmd. It is stored here -rem in order to allow TIKE to call out to the compiler while debugging. -if exist "%~dp0..\inst\node\dist\node.exe" ( - rem If running in developer/src/tike/: - set nodeexe="%~dp0..\inst\node\dist\node.exe" - set nodecli="%~dp0..\kmc\build\src\kmlmp.js" -) else if exist "%~dp0..\src\inst\node\dist\node.exe" ( - rem If running in developer/bin/: - set nodeexe="%~dp0..\src\inst\node\dist\node.exe" - set nodecli="%~dp0..\src\kmc\build\src\kmlmp.js" -) else ( - rem Cannot find node or kmlmp.js relative to execution path - echo Error: node.exe or kmlmp.js not found. - exit /b 1 -) - -%nodeexe% --enable-source-maps %nodecli% %* -exit /b %errorlevel% diff --git a/developer/src/tike/oskbuilder/UframeTouchLayoutBuilder.pas b/developer/src/tike/oskbuilder/UframeTouchLayoutBuilder.pas index 1bc2c5c8de..2ff812b350 100644 --- a/developer/src/tike/oskbuilder/UframeTouchLayoutBuilder.pas +++ b/developer/src/tike/oskbuilder/UframeTouchLayoutBuilder.pas @@ -355,8 +355,16 @@ begin with TStringList.Create do try - LoadFromFile(FBaseFileName, TEncoding.UTF8); - FNewLayoutJS := Text; + try + LoadFromFile(FBaseFileName, TEncoding.UTF8); + FNewLayoutJS := Text; + except + on E:Exception do + begin + ShowMessage(E.Message); + Exit(False); + end; + end; finally Free; end; diff --git a/docs/build/windows.md b/docs/build/windows.md index ccf74be55d..f485605f58 100644 --- a/docs/build/windows.md +++ b/docs/build/windows.md @@ -267,17 +267,35 @@ of appropriate node versions during builds. copying the relevant Delphi-built components into windows/bin folders from a compatible installed version of Keyman for testing and debugging purposes. -* Visual C++ 2019 Community or Professional +* Visual Studio 2022 Community (C++ native desktop workload) - ```ps1 - choco install visualstudio2019community visualstudio2019-workload-nativedesktop visualstudio2019buildtools + ```cmd + winget install --id=Microsoft.VisualStudio.2022.Community -e --override "--passive --add Microsoft.VisualStudio.Workload.NativeDesktop --add Microsoft.VisualStudio.Component.VC.Tools.ARM64 --add Microsoft.VisualStudio.Component.CppBuildInsights --add Microsoft.VisualStudio.Component.Debugger.JustInTime --add Microsoft.VisualStudio.Component.VC.ASAN --add Microsoft.VisualStudio.Component.VC.DiagnosticTools --add Microsoft.VisualStudio.Component.VC.TestAdapterForGoogleTest --add Microsoft.VisualStudio.Component.VC.Tools.x86.x64 --add Microsoft.VisualStudio.Component.Windows11SDK.26100 --add Microsoft.VisualStudio.Component.Windows11Sdk.WindowsPerformanceToolkit --add Microsoft.VisualStudio.Component.Windows10SDK.19041" ``` - * Verify required build tools are installed - * Run `Visual Studio Installer` - * Check the `Individual components` tab - * Verify `MSVC v142 - VS 2019 c++ x64/x86 build tools (Latest)` is installed. - If not, install it. + * You can omit the `--passive` parameter to open the installer dialog and + modify the selection before continuing with the install. + + * You can replace `--passive` with `--quiet` for a silent install (note that + the winget command returns before the Visual Studio Installer finishes, so + you won't be able to easily tell when installation completes; check Task + Manager for setup.exe). + + * If you prefer to use the Visual Studio Installer instead of the command + line install, then the following workloads and components should be included: + * Visual Studio core editor + * Desktop development with C++ + - C++ core desktop features + - MSVC v143 - VS 2022 C++ x64/x86 build tools (latest) + - C++ Build Insights + - Just-In-Time debugger + - C++ profiling tools + - Test Adapter for Google Test + - C++ AddressSanitizer + - Windows 10 SDK (10.0.19041.0) + - Windows 11 SDK (10.0.26100.6584) + * Under individual components, add: + - MSVC v143 - VS 2022 C++ ARM64/ARM64EC build tools (latest) Recommended: configure Visual Studio to use two-space tab stops: 1. Open the options dialog: Tools > Options. @@ -287,7 +305,7 @@ of appropriate node versions during builds. * Windows SDK (C++ Desktop Development) - https://developer.microsoft.com/en-us/windows/downloads/windows-sdk/ + This should be installed as a part of Visual Studio above **Required environment variables**: * `PATH` diff --git a/docs/minimum-versions.md b/docs/minimum-versions.md index 25b2733ce0..39bd6664d2 100644 --- a/docs/minimum-versions.md +++ b/docs/minimum-versions.md @@ -65,7 +65,7 @@ https://help.keyman.com/developer/engine/android/latest-version/ | KEYMAN_MIN_VERSION_MESON | 1.0.0 | | KEYMAN_MIN_VERSION_NODE_MAJOR | 20 | | KEYMAN_MIN_VERSION_NPM | 10.5.1 | -| KEYMAN_MIN_VERSION_VISUAL_STUDIO | 2019 | +| KEYMAN_MIN_VERSION_VISUAL_STUDIO | 2022 | | KEYMAN_VERSION_CLDR | 46 | | KEYMAN_VERSION_GRADLE | 8.12 | | KEYMAN_VERSION_ICU | 73.1 | diff --git a/docs/npm-packages.md b/docs/npm-packages.md index 8306130d36..9cee3696f6 100644 --- a/docs/npm-packages.md +++ b/docs/npm-packages.md @@ -3,16 +3,21 @@ This is a guide for how the various Keyman `npm` packages are developed and published. -`npm` packages are published on the CI (continuous integration) server. -Currently, we're using TeamCity for this. +`npm` packages are published through CI (continuous integration). This is done +through the `.github/workflows/npm-publish.yml` GitHub Action. Packages are **never** published from a developer's machine. ## List of current published npm packages +* See `resources/build/ci/npm-packages.inc.sh` for an authoritative list. + * `@keymanapp/common-types` -- located at `common/web/types` * `@keymanapp/keyman-version` -- located at `common/web/keyman-version` * `@keymanapp/kmc` -- located at `developer/src/kmc` +* `@keymanapp/kmc-analyze` -- located at `developer/src/kmc-analyze` +* `@keymanapp/kmc-copy` -- located at `developer/src/kmc-copy` +* `@keymanapp/kmc-generate` -- located at `developer/src/kmc-generate` * `@keymanapp/kmc-keyboard-info` -- located at `developer/src/kmc-keyboard-unfo` * `@keymanapp/kmc-kmn` -- located at `developer/src/kmc-kmn` * `@keymanapp/kmc-ldml` -- located at `developer/src/kmc-ldml` @@ -20,6 +25,7 @@ Packages are **never** published from a developer's machine. * `@keymanapp/kmc-model-info` -- located at `developer/src/kmc-model-info` * `@keymanapp/kmc-package` -- located at `developer/src/kmc-package` * `@keymanapp/langtags` -- located at `common/web/langtags` +* `@keymanapp/ldml-keyboard-constants` -- located at `core/include/dml` ### Deprecated npm packages @@ -34,22 +40,16 @@ Packages are **never** published from a developer's machine. ### In general -Before publishing, a package must be **built** and **tested** on the CI -server. - -This is typically done with: +Before publishing, a package must be **built** and **tested**. This is typically +done with: ```bash ./build.sh configure build test ``` -Once the build succeeds and the tests pass, you can publish! Use the following -script for this (**only on the CI server**!); during this, the version is set in -`package.json`: - -```bash -./build.sh publish -``` +Once the build succeeds and the tests pass, you can publish! Add the package to +`resources/build/ci/npm-packages.inc.sh` and it will be published in the next +alpha release build. It is then uploaded to the npm package directory. **Ensure that the compiled sources are included in the tarball**. For example: @@ -94,26 +94,5 @@ npm notice 740B tsconfig.json npm notice 449B tsconfig.kmc-base.json ``` -For every release of **Keyman Developer**, the CI publishes a release of -`@keymanapp/kmc`. The version number is locked with the particular version of -Keyman Developer. +For every release build, CI publishes a release of all packages. -### `builder_publish_npm` - -Publishes the package in `cwd` to npm - -If the `--dry-run` option is available and specified as a command-line -parameter, will do a dry run - -Note that `package.json` will be dirty after this command, as the `version` -field will be added to it, and @keymanapp dependency versions will also be -modified. This change should not be committed to the repository. - -If --npm-publish is set: -* then builder_publish_npm publishes to the public registry -* else builder_publish_npm creates a local tarball which can be used to test - -```bash - . "$KEYMAN_ROOT/resources/build/build-utils-ci.inc.sh" - builder_publish_npm -``` diff --git a/linux/debian/changelog b/linux/debian/changelog index ddb470e780..dd0f96f05a 100644 --- a/linux/debian/changelog +++ b/linux/debian/changelog @@ -1,9 +1,10 @@ -keyman (18.0.242-2) UNRELEASED; urgency=medium +keyman (18.0.243-1) unstable; urgency=medium * replace dbus-x11 dependency with default-dbus-session-bus | dbus-session-bus (closes: 1117068) + * New upstream release. - -- Eberhard Beilharz Mon, 06 Oct 2025 16:45:18 +0200 + -- Eberhard Beilharz Wed, 15 Oct 2025 12:09:24 +0200 keyman (18.0.242-1) unstable; urgency=medium diff --git a/mac/KeymanEngine4Mac/KeymanEngine4Mac/KME/OnScreenKeyboard/OSKView.m b/mac/KeymanEngine4Mac/KeymanEngine4Mac/KME/OnScreenKeyboard/OSKView.m index e98fe60663..e576d000b8 100644 --- a/mac/KeymanEngine4Mac/KeymanEngine4Mac/KME/OnScreenKeyboard/OSKView.m +++ b/mac/KeymanEngine4Mac/KeymanEngine4Mac/KME/OnScreenKeyboard/OSKView.m @@ -64,7 +64,7 @@ const int64_t OSK_EVENT_MODIFIER_MASK = 0x00000000FFFFFFFF; // Custom initialization [self initOSKKeys]; } - + return self; } @@ -76,26 +76,26 @@ const int64_t OSK_EVENT_MODIFIER_MASK = 0x00000000FFFFFFFF; - (void)drawRect:(NSRect)rect { os_log_debug([KMELogs oskLog], "OSKView drawRect: %{public}@", NSStringFromRect(rect)); - + CGContextRef context = (CGContextRef)[[NSGraphicsContext currentContext] CGContext]; CGContextSetLineJoin(context, kCGLineJoinRound); CGContextSetLineWidth(context, 1.0); CGColorRef cgClearColor = CGColorGetConstantColor(kCGColorClear); CGContextSetStrokeColorWithColor(context, cgClearColor); CGContextSetFillColorWithColor(context, cgClearColor); - + CGContextBeginPath(context); CGContextAddRect(context, CGRectMake(1.0, 1.0, rect.size.width-1.0, rect.size.height-1.0)); CGContextDrawPath(context, kCGPathStroke); - + CGContextBeginPath(context); CGContextAddRect(context, CGRectMake(1.0, 1.0, rect.size.width-1.0, rect.size.height-1.0)); CGContextClip(context); - + //TODO: gradient from clear to clear -- what does this do? NSColor *bgColor = [NSColor clearColor]; //[NSColor colorWithWhite:0.7 alpha:1.0]; NSColor *bgColor2 = [NSColor clearColor]; //[NSColor colorWithWhite:0.5 alpha:1.0]; - + CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB(); NSArray *gradientColors = [NSArray arrayWithObjects:(id)bgColor.CGColor, bgColor2.CGColor, nil]; CGFloat gradientLocations[] = {0, 1}; @@ -135,11 +135,11 @@ const int64_t OSK_EVENT_MODIFIER_MASK = 0x00000000FFFFFFFF; - (void)setKvk:(KVKFile *)kvk { os_log_debug([KMELogs oskLog], "OSKView setKvk, forces keyboard to re-layout"); _kvk = kvk; - + // Force the keyboard to re-layout _oskLayout = nil; _oskDefaultNKeys = nil; - + [self updateKeyLabelsForCurrentLayer]; } @@ -173,7 +173,7 @@ const int64_t OSK_EVENT_MODIFIER_MASK = 0x00000000FFFFFFFF; } py += keyHeight; } - + [self updateKeyLabelsForCurrentLayer]; } @@ -195,7 +195,7 @@ const int64_t OSK_EVENT_MODIFIER_MASK = 0x00000000FFFFFFFF; [[OSKKey alloc] initWithKeyCode:MVK_MINUS caption:@"-" scale:1.0], [[OSKKey alloc] initWithKeyCode:MVK_EQUAL caption:@"=" scale:1.0], [[OSKKey alloc] initWithKeyCode:MVK_BACKSPACE caption:@"⬅︎" scale:1.5], nil]; - + NSArray *row2 = [NSArray arrayWithObjects: [[OSKKey alloc] initWithKeyCode:MVK_TAB caption:@"↹" scale:1.5], [[OSKKey alloc] initWithKeyCode:MVK_Q caption:@"Q" scale:1.0], @@ -211,7 +211,7 @@ const int64_t OSK_EVENT_MODIFIER_MASK = 0x00000000FFFFFFFF; [[OSKKey alloc] initWithKeyCode:MVK_LEFT_BRACKET caption:@"[" scale:1.0], [[OSKKey alloc] initWithKeyCode:MVK_RIGHT_BRACKET caption:@"]" scale:1.0], [[OSKKey alloc] initWithKeyCode:MVK_BACKSLASH caption:@"\\" scale:1.0], nil]; - + NSArray *row3 = [NSArray arrayWithObjects: [[OSKKey alloc] initWithKeyCode:MVK_CAPS_LOCK caption:@"Caps Lock" scale:1.75], [[OSKKey alloc] initWithKeyCode:MVK_A caption:@"A" scale:1.0], @@ -226,14 +226,14 @@ const int64_t OSK_EVENT_MODIFIER_MASK = 0x00000000FFFFFFFF; [[OSKKey alloc] initWithKeyCode:MVK_SEMICOLON caption:@";" scale:1.0], [[OSKKey alloc] initWithKeyCode:MVK_QUOTE caption:@"'" scale:1.0], [[OSKKey alloc] initWithKeyCode:MVK_ENTER caption:@"↵" scale:1.75], nil]; - + NSArray *row4a = [self use102ndKey] ? [NSArray arrayWithObjects: [[OSKKey alloc] initWithKeyCode:MVK_LEFT_SHIFT caption:@"⇧" scale:1.25], [[OSKKey alloc] initWithKeyCode:MVK_OEM102 caption:@"\\" scale:1.0], nil] : [NSArray arrayWithObjects: [[OSKKey alloc] initWithKeyCode:MVK_LEFT_SHIFT caption:@"⇧" scale:2.25], nil]; - + NSArray *row4b = [NSArray arrayWithObjects: [[OSKKey alloc] initWithKeyCode:MVK_Z caption:@"Z" scale:1.0], [[OSKKey alloc] initWithKeyCode:MVK_X caption:@"X" scale:1.0], @@ -246,19 +246,19 @@ const int64_t OSK_EVENT_MODIFIER_MASK = 0x00000000FFFFFFFF; [[OSKKey alloc] initWithKeyCode:MVK_PERIOD caption:@"." scale:1.0], [[OSKKey alloc] initWithKeyCode:MVK_SLASH caption:@"/" scale:1.0], [[OSKKey alloc] initWithKeyCode:MVK_RIGHT_SHIFT caption:@"⇧" scale:2.25], nil]; - + NSArray *row4 = [row4a arrayByAddingObjectsFromArray:row4b]; - + NSArray *row5 = [NSArray arrayWithObjects: [[OSKKey alloc] initWithKeyCode:MVK_LEFT_CTRL caption:@"Ctrl" scale:1.75], [[OSKKey alloc] initWithKeyCode:MVK_LEFT_ALT caption:@"Alt" scale:1.5], [[OSKKey alloc] initWithKeyCode:MVK_SPACE caption:@"" scale:8.0], [[OSKKey alloc] initWithKeyCode:MVK_RIGHT_ALT caption:@"Alt" scale:1.5], [[OSKKey alloc] initWithKeyCode:MVK_RIGHT_CTRL caption:@"Ctrl" scale:1.75], nil]; - + _oskLayout = [NSArray arrayWithObjects:row1, row2, row3, row4, row5, nil]; } - + return _oskLayout; } @@ -266,7 +266,7 @@ const int64_t OSK_EVENT_MODIFIER_MASK = 0x00000000FFFFFFFF; if (_oskDefaultNKeys == nil) { os_log_debug([KMELogs oskLog], "oskDefaultNKeys -> creating new arrays of default number OSKKey objects"); NSMutableArray *defNKeys = [[NSMutableArray alloc] initWithCapacity:0]; - + // row 1 NKey *nkey1 = [[NKey alloc] init]; nkey1.typeFlags = 2; nkey1.modifierFlags = 0; nkey1.keyCode = VK_GRAVE; nkey1.text = @"`"; nkey1.bitmap = nil; NKey *nkey2 = [[NKey alloc] init]; nkey2.typeFlags = 2; nkey2.modifierFlags = 1; nkey2.keyCode = VK_GRAVE; nkey2.text = @"~"; nkey2.bitmap = nil; @@ -307,7 +307,7 @@ const int64_t OSK_EVENT_MODIFIER_MASK = 0x00000000FFFFFFFF; nkey1 = [[NKey alloc] init]; nkey1.typeFlags = 2; nkey1.modifierFlags = 0; nkey1.keyCode = VK_EQUAL; nkey1.text = @"="; nkey1.bitmap = nil; nkey2 = [[NKey alloc] init]; nkey2.typeFlags = 2; nkey2.modifierFlags = 1; nkey2.keyCode = VK_EQUAL; nkey2.text = @"+"; nkey2.bitmap = nil; [defNKeys addObjectsFromArray:@[nkey1, nkey2]]; - + // row 2 nkey1 = [[NKey alloc] init]; nkey1.typeFlags = 2; nkey1.modifierFlags = 0; nkey1.keyCode = VK_KEY_Q; nkey1.text = @"q"; nkey1.bitmap = nil; nkey2 = [[NKey alloc] init]; nkey2.typeFlags = 2; nkey2.modifierFlags = 1; nkey2.keyCode = VK_KEY_Q; nkey2.text = @"Q"; nkey2.bitmap = nil; @@ -348,7 +348,7 @@ const int64_t OSK_EVENT_MODIFIER_MASK = 0x00000000FFFFFFFF; nkey1 = [[NKey alloc] init]; nkey1.typeFlags = 2; nkey1.modifierFlags = 0; nkey1.keyCode = VK_BACKSLASH; nkey1.text = @"\\"; nkey1.bitmap = nil; nkey2 = [[NKey alloc] init]; nkey2.typeFlags = 2; nkey2.modifierFlags = 1; nkey2.keyCode = VK_BACKSLASH; nkey2.text = @"|"; nkey2.bitmap = nil; [defNKeys addObjectsFromArray:@[nkey1, nkey2]]; - + // row 3 nkey1 = [[NKey alloc] init]; nkey1.typeFlags = 2; nkey1.modifierFlags = 0; nkey1.keyCode = VK_KEY_A; nkey1.text = @"a"; nkey1.bitmap = nil; nkey2 = [[NKey alloc] init]; nkey2.typeFlags = 2; nkey2.modifierFlags = 1; nkey2.keyCode = VK_KEY_A; nkey2.text = @"A"; nkey2.bitmap = nil; @@ -383,7 +383,7 @@ const int64_t OSK_EVENT_MODIFIER_MASK = 0x00000000FFFFFFFF; nkey1 = [[NKey alloc] init]; nkey1.typeFlags = 2; nkey1.modifierFlags = 0; nkey1.keyCode = VK_QUOTE; nkey1.text = @"'"; nkey1.bitmap = nil; nkey2 = [[NKey alloc] init]; nkey2.typeFlags = 2; nkey2.modifierFlags = 1; nkey2.keyCode = VK_QUOTE; nkey2.text = @"\""; nkey2.bitmap = nil; [defNKeys addObjectsFromArray:@[nkey1, nkey2]]; - + if([self use102ndKey]) { nkey1 = [[NKey alloc] init]; nkey1.typeFlags = 2; nkey1.modifierFlags = 0; nkey1.keyCode = VK_OEM_102; nkey1.text = @"\\"; nkey1.bitmap = nil; nkey2 = [[NKey alloc] init]; nkey2.typeFlags = 2; nkey2.modifierFlags = 1; nkey2.keyCode = VK_OEM_102; nkey2.text = @"|"; nkey2.bitmap = nil; @@ -420,10 +420,10 @@ const int64_t OSK_EVENT_MODIFIER_MASK = 0x00000000FFFFFFFF; nkey1 = [[NKey alloc] init]; nkey1.typeFlags = 2; nkey1.modifierFlags = 0; nkey1.keyCode = VK_SLASH; nkey1.text = @"/"; nkey1.bitmap = nil; nkey2 = [[NKey alloc] init]; nkey2.typeFlags = 2; nkey2.modifierFlags = 1; nkey2.keyCode = VK_SLASH; nkey2.text = @"?"; nkey2.bitmap = nil; [defNKeys addObjectsFromArray:@[nkey1, nkey2]]; - + _oskDefaultNKeys = [[NSArray alloc] initWithArray:defNKeys]; } - + return _oskDefaultNKeys; } @@ -471,7 +471,7 @@ const int64_t OSK_EVENT_MODIFIER_MASK = 0x00000000FFFFFFFF; CGEventPostToPid(processId, keyUpEvent); CFRelease(keyDownEvent); CFRelease(keyUpEvent); - + CFRelease(source); } else { @@ -501,7 +501,7 @@ const int64_t OSK_EVENT_MODIFIER_MASK = 0x00000000FFFFFFFF; BOOL shift = self.physicalShiftState | self.oskShiftState; BOOL option = self.physicalOptionState | self.oskOptionState; BOOL control = self.physicalControlState | self.oskControlState; - + return [self getEventModifierFlags:shift optionFlag:option controlFlag:control]; } @@ -510,7 +510,7 @@ const int64_t OSK_EVENT_MODIFIER_MASK = 0x00000000FFFFFFFF; */ - (NSEventModifierFlags)getEventModifierFlags:(BOOL)shift optionFlag:(BOOL)option controlFlag:(BOOL)control { NSEventModifierFlags modifierFlags = 0; - + if (shift) { modifierFlags = modifierFlags | NSEventModifierFlagShift; } @@ -524,7 +524,7 @@ const int64_t OSK_EVENT_MODIFIER_MASK = 0x00000000FFFFFFFF; if (control) { modifierFlags = modifierFlags | NSEventModifierFlagControl; } - + return modifierFlags; } @@ -551,7 +551,7 @@ const int64_t OSK_EVENT_MODIFIER_MASK = 0x00000000FFFFFFFF; NSView *view = [self viewWithTag:event.keyCode|0x1000]; if (view == nil || ![view isKindOfClass:[KeyView class]]) return; - + KeyView *keyView = (KeyView *)view; if (event.type == NSEventTypeKeyDown) [keyView setKeyPressed:YES]; @@ -570,7 +570,7 @@ const int64_t OSK_EVENT_MODIFIER_MASK = 0x00000000FFFFFFFF; BOOL shift = self.physicalShiftState | self.oskShiftState; BOOL option = self.physicalOptionState | self.oskOptionState; BOOL control = self.physicalControlState | self.oskControlState; - + return [self getKeymanModifierFlags:shift optionFlag:option controlFlag:control]; } @@ -592,7 +592,7 @@ const int64_t OSK_EVENT_MODIFIER_MASK = 0x00000000FFFFFFFF; if (control) { flags |= KVKS_RCTRL; } - + return flags; } @@ -602,15 +602,15 @@ const int64_t OSK_EVENT_MODIFIER_MASK = 0x00000000FFFFFFFF; */ - (void)updateKeyLabelsForCurrentLayer { os_log_debug([KMELogs oskLog], "OSKView updateKeyLabelsForState, phsyical modifiers [shift: %d, option: %d, control: %d]\nosk modifiers [shift: %d, option: %d, control: %d]", self.physicalShiftState, self.physicalOptionState, self.physicalControlState, self.oskShiftState, self.oskOptionState, self.oskControlState); - + [self resetKeyLabels]; NSMutableArray *mKeys = [[self keyTags] mutableCopy]; NSArray *nkeys = [self.kvk keys]; if (nkeys == nil) nkeys = self.oskDefaultNKeys; - + WORD keymanFlagsForCurrentLayer = [self getKeymanModifierFlagsForCurrentLayer]; - + NSString *ansiFont = [self ansiFont]; NSString *unicodeFont = [self unicodeFont]; unsigned short keyCode; @@ -622,9 +622,8 @@ const int64_t OSK_EVENT_MODIFIER_MASK = 0x00000000FFFFFFFF; NSView *view = [self viewWithTag:keyCode|0x1000]; if (view == nil || ![view isKindOfClass:[KeyView class]]) continue; - + KeyView *keyView = (KeyView *)view; - [keyView setLabelFont:ansiFont]; if (nkey.typeFlags & KVKK_UNICODE) { [keyView setLabelText:nkey.text]; NSString* label = nkey.text; @@ -632,12 +631,16 @@ const int64_t OSK_EVENT_MODIFIER_MASK = 0x00000000FFFFFFFF; os_log_debug([KMELogs keyLog], "setLabelText to %{public}@, utf8data %{public}@", label, data); [keyView setLabelFont:unicodeFont]; [mKeys removeObject:[NSNumber numberWithInteger:(keyCode|0x1000)]]; + } else { + // This means it is a key definition for a non-Unicode layout. + // We do not support non-Unicode keyboards in Keyman for macOS. + continue; } - + if (nkey.typeFlags & KVKK_BITMAP) { [keyView setBitmap:nkey.bitmap]; } - + [keyView setNeedsDisplay:YES]; } } @@ -647,7 +650,7 @@ const int64_t OSK_EVENT_MODIFIER_MASK = 0x00000000FFFFFFFF; NSView *view = [self viewWithTag:[t integerValue]|0x1000]; if (view == nil || ![view isKindOfClass:[KeyView class]]) continue; - + KeyView *keyView = (KeyView *)view; [keyView setLabelText:@""]; }*/ @@ -659,10 +662,10 @@ const int64_t OSK_EVENT_MODIFIER_MASK = 0x00000000FFFFFFFF; for (NSView *view in views) { if (![view isKindOfClass:[KeyView class]]) continue; - + [keyTags addObject:[NSNumber numberWithInteger:[view tag]]]; } - + return keyTags; } @@ -671,7 +674,7 @@ const int64_t OSK_EVENT_MODIFIER_MASK = 0x00000000FFFFFFFF; for (NSView *view in views) { if (![view isKindOfClass:[KeyView class]]) continue; - + [(KeyView *)view setKey:[(KeyView *)view key]]; [(KeyView *)view setBitmap:nil]; [(KeyView *)view setNeedsDisplay:YES]; @@ -687,7 +690,7 @@ const int64_t OSK_EVENT_MODIFIER_MASK = 0x00000000FFFFFFFF; * The state of the physical key overrides the modifier key clicked in the OSK. */ _oskShiftState = NO; - + os_log_debug([KMELogs oskLog], "hardware shift key released"); [self updateKeyLabelsForCurrentLayer]; [self updateShiftKeysForState]; @@ -705,7 +708,7 @@ const int64_t OSK_EVENT_MODIFIER_MASK = 0x00000000FFFFFFFF; - (void)setPhysicalOptionState:(BOOL)state { if (_physicalOptionState != state) { _physicalOptionState = state; - + /** * When setting the physical option state, clear the OSK option state * The state of the physical key overrides the modifier key clicked in the OSK. @@ -727,7 +730,7 @@ const int64_t OSK_EVENT_MODIFIER_MASK = 0x00000000FFFFFFFF; - (void)setPhysicalControlState:(BOOL)state { if (_physicalControlState != state) { _physicalControlState = state; - + /** * When setting the physical control state, clear the OSK control state * The state of the physical key overrides the modifier key clicked in the OSK. @@ -793,7 +796,7 @@ const int64_t OSK_EVENT_MODIFIER_MASK = 0x00000000FFFFFFFF; break; } } - + return keyCode; } diff --git a/mac/README.md b/mac/README.md index ef4c0d4b41..f15997e827 100644 --- a/mac/README.md +++ b/mac/README.md @@ -27,8 +27,8 @@ keyboard input. You have two options for local builds: Keyman must be signed then notarized by Apple, even for local test builds. This requires additional configuration for your build environment. -1. First, open XCode, Preferences, Accounts, and select Manage Certificates for the identity - you wish to use for signing. Click **+** and select **Developer ID Application**. A +1. First, open XCode, Settings, Accounts, and select Manage Certificates for the identity + you wish to use for signing. Click **+** and select **Apple Development**. A certificate will then be generated and listed in your Keychain. 2. Find the SHA-1 hash. To find the certificate in terminal: @@ -64,23 +64,17 @@ configuration for your build environment. To build Keyman for macOS, do the following: 1. Open a Terminal window. -2. cd to **keyman/mac**. **build.sh** must be run in the directory containing the script. -3. Build using `./build.sh -no-codesign`. Run `./build.sh -help` to see all options. - * If you have signing credentials from the core development team, you can build a signed - version by omitting `-no-codesign`. Somewhat misleadingly, `-no-codesign` only stops - automatic signing using the certificate maintained by the core development team! - * If you want to deploy, you will need to also add `-config Release`, as a Debug build cannot be notarized. +2. Build using `mac/build.sh clean configure build` Note: If Carthage prompts you to allow it access to your github credentials, it's fine to click Deny. ### Running Keyman -1. Deploy Keyman locally using `./build.sh -deploy local -deploy-only`. +1. Deploy Keyman locally using `mac/build.sh install`. * This will notarize the app, signing with your local credentials if not already signed, and copy **keyman/mac/Keyman4MacIM/build/Debug/Keyman.app** to **~/Library/Input Methods** 2. If running for the first time, follow the installation instructions at [Install Keyman for macOS]. -You can also use `./build.sh -no-codesign -deploy local` to do a single-step build, notarize, -and deploy (see above for faster options). +You can also use `mac/build.sh build install` to do a single-step build, notarize, and deploy (see above for faster options). ### Compiling from Xcode diff --git a/package-lock.json b/package-lock.json index 6d78fc0aec..76485081c2 100644 --- a/package-lock.json +++ b/package-lock.json @@ -291,9 +291,7 @@ "supports-color": "^9.4.0" }, "bin": { - "kmc": "build/src/kmc.js", - "kmlmc": "build/src/kmlmc.js", - "kmlmp": "build/src/kmlmp.js" + "kmc": "build/src/kmc.js" }, "devDependencies": { "@sentry/cli": "^2.31.0", diff --git a/package.json b/package.json index 1245931bec..e33fd5b41b 100644 --- a/package.json +++ b/package.json @@ -72,6 +72,10 @@ "fast-json-patch": "^3.1.1" } }, + "repository": { + "type": "git", + "url": "git+https://github.com/keymanapp/keyman.git" + }, "engines": { "node": "20.16.0" } diff --git a/resources/build/ci/cancel-builds/trigger_definitions.mjs b/resources/build/ci/cancel-builds/trigger_definitions.mjs index f6acdf91bb..aef0526688 100644 --- a/resources/build/ci/cancel-builds/trigger_definitions.mjs +++ b/resources/build/ci/cancel-builds/trigger_definitions.mjs @@ -6,7 +6,7 @@ export const testBuildConfigurations = { 'mac': ['Keyman_KeymanMac_PullRequests', 'Keyman_Common_KPAPI_TestPullRequests_macOS'], 'windows': ['KeymanDesktop_TestPullRequests', 'KeymanDesktop_TestPrRenderOnScreenKeyboards', 'Keyman_Common_KPAPI_TestPullRequests_Windows'], 'web': ['Keymanweb_TestPullRequests', 'Keyman_Common_KPAPI_TestPullRequests_WASM'], - 'developer': ['Keyman_Developer_Test'], + 'developer': ['Keyman_Developer_Test', 'npm-publish_GitHub'], 'common_web': ['Keyman_Test_Common_Web'], 'common_windows': ['Keyman_Test_Common_Windows'], diff --git a/resources/build/ci/ci-publish.inc.sh b/resources/build/ci/ci-publish.inc.sh index d8fc1e77a2..2785fead35 100644 --- a/resources/build/ci/ci-publish.inc.sh +++ b/resources/build/ci/ci-publish.inc.sh @@ -8,39 +8,10 @@ . "$KEYMAN_ROOT/resources/build/jq.inc.sh" -# -# Publishes the package in `cwd` to npm -# -# If the `--dry-run` option is available and specified as a command-line -# parameter, will do a dry run -# -# Note that `package.json` will be dirty after this command, as the `version` -# field will be added to it, and @keymanapp dependency versions will also be -# modified. This change should not be committed to the repository. -# -# If --npm-publish is set: -# * then ci_publish_npm publishes to the public registry -# * else ci_publish_npm creates a local tarball which can be used to test -# -# Usage: -# ```bash -# ci_publish_npm -# ``` -# -function ci_publish_npm() { - if builder_has_option --npm-publish; then - # Require --dry-run if local or test to avoid accidentally clobbering npm packages - if [[ $KEYMAN_VERSION_ENVIRONMENT =~ local|test ]] && ! builder_has_option --dry-run; then - builder_die "publish --npm-publish must use --dry-run flag for local or test builds" - fi - _ci_publish_npm_package publish - else - _ci_publish_npm_package pack - fi -} - -function _ci_publish_npm_package() { - local action=$1 +# Used only by npm-publish.sh +function ci_publish_npm_package() { + local action="$1" + local package="$2" local dist_tag=$KEYMAN_TIER dry_run= if [[ $KEYMAN_TIER == stable ]]; then @@ -51,6 +22,8 @@ function _ci_publish_npm_package() { dry_run=--dry-run fi + pushd "${KEYMAN_ROOT}/${package}" >/dev/null + _ci_publish_cache_package_json _ci_write_npm_version _ci_prepublish @@ -62,12 +35,14 @@ function _ci_publish_npm_package() { if [[ $action == pack ]]; then # We can use --publish-to-pack to locally test a package # before publishing to the package registry - echo "Packing $dry_run npm package $THIS_SCRIPT_IDENTIFIER with tag $dist_tag" + echo "Packing $dry_run npm package ${package} with tag $dist_tag" npm pack $dry_run --access public --tag $dist_tag else # $action == publish - echo "Publishing $dry_run npm package $THIS_SCRIPT_IDENTIFIER with tag $dist_tag" + echo "Publishing $dry_run npm package ${package} with tag $dist_tag" npm publish $dry_run --access public --tag $dist_tag fi + + popd >/dev/null } function _ci_write_npm_version() { diff --git a/developer/src/packages.inc.sh b/resources/build/ci/npm-packages.inc.sh similarity index 78% rename from developer/src/packages.inc.sh rename to resources/build/ci/npm-packages.inc.sh index 62993c5ab9..a1c4eecd8b 100644 --- a/developer/src/packages.inc.sh +++ b/resources/build/ci/npm-packages.inc.sh @@ -1,7 +1,8 @@ +# +# Keyman is copyright (C) SIL Global. MIT License. +# # List of all NPM packages that need to be published # -# TODO: this should really be somewhere else, but right now Developer CI is -# responsible for pulling the publish lever readonly PACKAGES=( common/web/keyman-version diff --git a/resources/build/ci/npm-publish.sh b/resources/build/ci/npm-publish.sh new file mode 100755 index 0000000000..e9b522e2aa --- /dev/null +++ b/resources/build/ci/npm-publish.sh @@ -0,0 +1,148 @@ +#!/usr/bin/env bash +# +# Keyman is copyright (C) SIL Global. MIT License. +# +# Publish all the @keymanapp packages listed in npm-packages.inc.sh +# +# If the `--dry-run` option is available and specified as a command-line +# parameter, will do a dry run +# +# Note that `package.json` will be dirty after this command, as the `version` +# field will be added to it, and @keymanapp dependency versions will also be +# modified. This change should not be committed to the repository. +# +# If `publish` is called: +# * then ci_publish_npm publishes to the public registry +# * else ci_publish_npm creates a local tarball which can be used to test +# +## START STANDARD BUILD SCRIPT INCLUDE +# adjust relative paths as necessary +THIS_SCRIPT="$(readlink -f "${BASH_SOURCE[0]}")" +. "${THIS_SCRIPT%/*}/../../../resources/build/builder-full.inc.sh" +## END STANDARD BUILD SCRIPT INCLUDE + +. "$KEYMAN_ROOT/resources/build/ci/ci-publish.inc.sh" +. "$KEYMAN_ROOT/resources/build/ci/npm-packages.inc.sh" +. "$KEYMAN_ROOT/resources/build/minimum-versions.inc.sh" + +builder_describe \ + "Publish @keymanapp packages to NPM" \ + "configure Install required modules for build on GHA" \ + "pack Pack NPM packages to a .tgz for verification" \ + "publish Publish NPM packages to the NPM Registry" \ + "--dry-run Don't publish/pack anything, just dry run" + +builder_parse "$@" + +#------------------------------------------------------------------------------------------------------------------- + +function do_pack() { + do_package_builds + do_pack_or_publish pack +} + +function do_package_builds() { + local npm_package_path + for npm_package_path in "${PACKAGES[@]}"; do + builder_heading "Building ${npm_package_path}" + "${KEYMAN_ROOT}/${npm_package_path}/build.sh" build test + done +} + +function inject_sourcemaps() { + local SOURCEMAP_PATHS + SOURCEMAP_PATHS=( "${PACKAGES[@]}" ) + SOURCEMAP_PATHS=( "${SOURCEMAP_PATHS[@]/%//build}" ) + + builder_heading "Injecting sourcemaps" + + pushd "${KEYMAN_ROOT}" + + sentry-cli sourcemaps inject \ + --org keyman \ + --project keyman-developer \ + --release "$KEYMAN_VERSION_GIT_TAG" \ + "${SOURCEMAP_PATHS[@]}" + + if [[ "${GHA_TEST_BUILD+x}" == false ]]; then + builder_heading "Uploading sourcemaps" + + sentry-cli sourcemaps upload \ + --no-dedupe \ + --org keyman \ + --project keyman-developer \ + --release "$KEYMAN_VERSION_GIT_TAG" \ + --ext js --ext mjs --ext ts --ext map \ + "${SOURCEMAP_PATHS[@]}" + else + builder_heading "Skipping upload of sourcemaps (test build)" + fi + + popd +} + +function do_pack_or_publish() { + local npm_action="$1" + local npm_package_path + + inject_sourcemaps + + for npm_package_path in "${PACKAGES[@]}"; do + builder_heading "npm ${npm_action} ${npm_package_path}" + ci_publish_npm_package "${npm_action}" "${npm_package_path}" + done +} + +function do_publish() { + if [[ $KEYMAN_VERSION_ENVIRONMENT =~ local|test ]] && ! builder_has_option --dry-run; then + builder_die "publish must use --dry-run flag for local or test builds" + fi + + do_package_builds + do_pack_or_publish publish +} + +function install_emscripten() { + builder_heading "Installing emscripten" + + local EMSDK_TEMP + EMSDK_TEMP=$(mktemp -d) + pushd "${EMSDK_TEMP}" + git clone https://github.com/emscripten-core/emsdk.git + cd emsdk + ./emsdk install "${KEYMAN_MIN_VERSION_EMSCRIPTEN}" + ./emsdk activate "${KEYMAN_MIN_VERSION_EMSCRIPTEN}" + cd upstream/emscripten + npm install + echo "EMSCRIPTEN_BASE=$(pwd)" >> $GITHUB_ENV + EMSCRIPTEN_BASE="$(pwd)" + export EMSCRIPTEN_BASE + popd +} + +function install_meson() { + builder_heading "Installing meson" + + builder_echo "Starting apt-get update + install meson" + sudo apt-get update + sudo apt-get install meson + echo "meson version:" + meson -v +} + +function install_sentry_cli() { + builder_heading "Installing sentry-cli" + + curl -sL https://sentry.io/get-cli/ | SENTRY_CLI_VERSION="2.57.0" sh + sentry-cli --version +} + +function do_configure() { + install_meson + install_emscripten + install_sentry_cli +} + +builder_run_action configure do_configure +builder_run_action pack do_pack +builder_run_action publish do_publish diff --git a/resources/build/ci/trigger-definitions.inc.sh b/resources/build/ci/trigger-definitions.inc.sh index 7492138434..ab08734804 100644 --- a/resources/build/ci/trigger-definitions.inc.sh +++ b/resources/build/ci/trigger-definitions.inc.sh @@ -89,7 +89,7 @@ bc_test_linux=(KeymanLinux_TestPullRequests Keyman_Linux_Test_Integration Keyman bc_test_mac=(Keyman_KeymanMac_PullRequests Keyman_Common_KPAPI_TestPullRequests_macOS) bc_test_windows=(KeymanDesktop_TestPullRequests KeymanDesktop_TestPrRenderOnScreenKeyboards Keyman_Common_KPAPI_TestPullRequests_Windows) bc_test_web=(Keymanweb_TestPullRequests Keyman_Common_KPAPI_TestPullRequests_WASM) -bc_test_developer=(Keyman_Developer_Test Keyman_Test_Developer_Mac Keyman_Test_Developer_Linux) +bc_test_developer=(Keyman_Developer_Test Keyman_Test_Developer_Mac Keyman_Test_Developer_Linux npm-publish_GitHub) bc_test_common_web=(Keyman_Test_Common_Web) bc_test_common_windows=(Keyman_Test_Common_Windows) @@ -116,7 +116,7 @@ bc_master_linux=(KeymanLinux_Master deb-release-packaging_GitHub build-test-publ bc_master_mac=(KeymanMac_Master) bc_master_windows=(Keyman_Build) bc_master_web=(Keymanweb_Build) -bc_master_developer=(Keyman_Developer_Release) +bc_master_developer=(Keyman_Developer_Release npm-publish_GitHub) vcs_master=HttpsGithubComKeymanappKeyman @@ -128,7 +128,7 @@ bc_beta_linux=(KeymanLinux_Master deb-release-packaging_GitHub) bc_beta_mac=(KeymanMac_Master) bc_beta_windows=(Keyman_Build) bc_beta_web=(Keymanweb_Build) -bc_beta_developer=(Keyman_Developer_Release) +bc_beta_developer=(Keyman_Developer_Release npm-publish_GitHub) vcs_beta=HttpsGithubComKeymanappKeyman @@ -140,7 +140,7 @@ bc_stable_18_0_linux=(KeymanLinux_Master deb-release-packaging_GitHub) bc_stable_18_0_mac=(KeymanMac_Master) bc_stable_18_0_windows=(Keyman_Build) bc_stable_18_0_web=(Keymanweb_Build) -bc_stable_18_0_developer=(Keyman_Developer_Release) +bc_stable_18_0_developer=(Keyman_Developer_Release npm-publish_GitHub) vcs_stable_18_0=HttpsGithubComKeymanappKeyman @@ -152,6 +152,6 @@ bc_stable_19_0_linux=(KeymanLinux_Master deb-release-packaging_GitHub) bc_stable_19_0_mac=(KeymanMac_Master) bc_stable_19_0_windows=(Keyman_Build) bc_stable_19_0_web=(Keymanweb_Build) -bc_stable_19_0_developer=(Keyman_Developer_Release) +bc_stable_19_0_developer=(Keyman_Developer_Release npm-publish_GitHub) vcs_stable_19_0=HttpsGithubComKeymanappKeyman diff --git a/resources/build/minimum-versions.inc.sh b/resources/build/minimum-versions.inc.sh index c3b0a34519..65778fece8 100644 --- a/resources/build/minimum-versions.inc.sh +++ b/resources/build/minimum-versions.inc.sh @@ -29,7 +29,7 @@ KEYMAN_MIN_TARGET_VERSION_WEB_SAFARI=13.0 # iOS 13.0, macOS 10.13.6+ KEYMAN_MIN_VERSION_NODE_MAJOR=20 # node version source of truth is /package.json:/engines/node; use KEYMAN_USE_NVM to automatically update KEYMAN_MIN_VERSION_NPM=10.5.1 # 10.5.0 has bug, discussed in #10350 KEYMAN_MIN_VERSION_EMSCRIPTEN=3.1.64 # Use KEYMAN_USE_EMSDK to automatically update to this version -KEYMAN_MIN_VERSION_VISUAL_STUDIO=2019 +KEYMAN_MIN_VERSION_VISUAL_STUDIO=2022 # Visual Studio 2022, see /docs/build/windows.md for workloads and components KEYMAN_MIN_VERSION_MESON=1.0.0 KEYMAN_VERSION_GRADLE=8.12 # See /android/KMEA/gradle/wrapper/gradle-wrapper.properties diff --git a/resources/build/node.inc.sh b/resources/build/node.inc.sh index f338718cdf..4d70f2445b 100644 --- a/resources/build/node.inc.sh +++ b/resources/build/node.inc.sh @@ -22,7 +22,12 @@ node_select_version_and_npm_ci() { # Also, a developer can set KEYMAN_USE_NVM variable to get this behaviour # automatically too (see /docs/build/node.md) if [[ "$KEYMAN_VERSION_ENVIRONMENT" != local || ! -z "${KEYMAN_USE_NVM+x}" ]]; then - _node_select_version_with_nvm + # For npm publishing, we currently need to use an alternate version of node + # that includes npm 11.5.1 or later (see #15040). Once we move to node v24, + # we can probably remove this check + if [[ -z "${KEYMAN_CI_SKIP_NVM+x}" ]]; then + _node_select_version_with_nvm + fi fi # Check if Node.JS/npm is installed. diff --git a/resources/build/pr-build-status/pr-build-status.mjs b/resources/build/pr-build-status/pr-build-status.mjs index 137a17cea5..2af588f206 100644 --- a/resources/build/pr-build-status/pr-build-status.mjs +++ b/resources/build/pr-build-status/pr-build-status.mjs @@ -52,6 +52,8 @@ summary += addStatus(o, 'check', status.context, status.state); } else if(status.context == 'Ubuntu Packaging') { summary += addStatus(o, 'build', status.context, status.state); + } else if(status.context == 'npm pack/publish') { + summary += addStatus(o, 'build', status.context, status.state); } else if(status.context == 'check/web/file-size') { // Ignore check/web/file-size -- we won't block automerge for this at this point summary += addLog(`Skipping ${status.context}`); diff --git a/resources/devbox/macos/keyman.macos.env.sh b/resources/devbox/macos/keyman.macos.env.sh index 5ffb36eaaf..3c6a93634c 100755 --- a/resources/devbox/macos/keyman.macos.env.sh +++ b/resources/devbox/macos/keyman.macos.env.sh @@ -15,7 +15,7 @@ export PATH=$ANDROID_HOME/platform-tools:$PATH export PATH=$ANDROID_HOME/cmdline-tools/latest/bin:$PATH export PATH=$ANDROID_HOME/build-tools/30.0.3:$PATH -if [ -z "$HOMEBREW_PREFIX" ]; then +if [ -z "${HOMEBREW_PREFIX+x}" ]; then HOMEBREW_PREFIX=`brew --prefix` fi diff --git a/resources/docker-images/android/Dockerfile b/resources/docker-images/android/Dockerfile index be99a2f247..7261ed97dc 100644 --- a/resources/docker-images/android/Dockerfile +++ b/resources/docker-images/android/Dockerfile @@ -36,11 +36,27 @@ EOF # Finish bashwrapper script and adjust permissions RUN <> /usr/bin/bashwrapper +if [[ -v CHANGE_PERMISSIONS ]]; then + uid=\$(stat -c "%u" /home/build/build) + gid=\$(stat -c "%g" /home/build/build) + if [[ "\${uid}" != "\$(id -u)" && "\${gid}" != "\$(id -g)" ]]; then + echo "Adjusting build directory ownership to uid/gid \$(id -un):\$(id -gn)" + sudo chown -R build:build /home/build/build + fi +fi + if [[ "\$@" =~ test ]] && [ -f /usr/bin/run-tests.sh ]; then /usr/bin/run-tests.sh "\${@:-bash}" else "\${@:-bash}" fi + +if [[ -v CHANGE_PERMISSIONS ]]; then + if [[ "\${uid}" != "\$(id -u)" && "\${gid}" != "\$(id -g)" ]]; then + echo "Reverting build directory ownership to uid/gid \${uid}:\${gid}" + sudo chown -R \${uid}:\${gid} /home/build/build + fi +fi EOF # now, switch to build user diff --git a/resources/docker-images/base/Dockerfile b/resources/docker-images/base/Dockerfile index 835806d63c..0cba2b73dc 100644 --- a/resources/docker-images/base/Dockerfile +++ b/resources/docker-images/base/Dockerfile @@ -53,6 +53,7 @@ EOF # Install NVM RUN NVM_RELEASE=$(curl -s https://api.github.com/repos/nvm-sh/nvm/releases/latest | grep tag_name | cut -d : -f 2 | cut -d '"' -f 2) && \ curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/${NVM_RELEASE}/install.sh | bash +RUN chmod -R +x,+r $HOME/ RUN <> /usr/bin/bashwrapper PATH=/home/build/.keyman/node:\$PATH export NVM_DIR="$HOME/.nvm" diff --git a/resources/docker-images/build.sh b/resources/docker-images/build.sh index 33f638ed6a..c07e732efb 100755 --- a/resources/docker-images/build.sh +++ b/resources/docker-images/build.sh @@ -105,7 +105,7 @@ if builder_has_action build; then fi builder_run_action test:core test_action core -# builder_run_action test:linux test_action linux +builder_run_action test:linux test_action linux builder_run_action test:web test_action web # Android uses artifacts from web, so it has to come after web builder_run_action test:android test_action android diff --git a/resources/docker-images/core/Dockerfile b/resources/docker-images/core/Dockerfile index 0519540865..0589b8c2ee 100644 --- a/resources/docker-images/core/Dockerfile +++ b/resources/docker-images/core/Dockerfile @@ -34,10 +34,26 @@ RUN echo "export EMSCRIPTEN_BASE=/home/build/emsdk/upstream/emscripten" >> /usr/ # Finish bashwrapper script and adjust permissions RUN <> /usr/bin/bashwrapper -if [[ "\$@" =~ test ]] && [ -f /usr/bin/run-tests.sh ]; then - /usr/bin/run-tests.sh "\${@:-bash}" -else - "\${@:-bash}" +if [[ -v CHANGE_PERMISSIONS ]]; then + uid=\$(stat -c "%u" /home/build/build) + gid=\$(stat -c "%g" /home/build/build) + if [[ "\${uid}" != "\$(id -u)" && "\${gid}" != "\$(id -g)" ]]; then + echo "Adjusting build directory ownership to uid/gid \$(id -un):\$(id -gn)" + sudo chown -R build:build /home/build/build + fi +fi + + if [[ "\$@" =~ test ]] && [ -f /usr/bin/run-tests.sh ]; then + /usr/bin/run-tests.sh "\${@:-bash}" + else + "\${@:-bash}" + fi + +if [[ -v CHANGE_PERMISSIONS ]]; then + if [[ "\${uid}" != "\$(id -u)" && "\${gid}" != "\$(id -g)" ]]; then + echo "Reverting build directory ownership to uid/gid \${uid}:\${gid}" + sudo chown -R \${uid}:\${gid} /home/build/build + fi fi EOF diff --git a/resources/docker-images/developer/Dockerfile b/resources/docker-images/developer/Dockerfile index bfd25428e4..19c69c5e98 100644 --- a/resources/docker-images/developer/Dockerfile +++ b/resources/docker-images/developer/Dockerfile @@ -34,11 +34,27 @@ RUN echo "export EMSCRIPTEN_BASE=/home/build/emsdk/upstream/emscripten" >> /usr/ # Finish bashwrapper script and adjust permissions RUN <> /usr/bin/bashwrapper +if [[ -v CHANGE_PERMISSIONS ]]; then + uid=\$(stat -c "%u" /home/build/build) + gid=\$(stat -c "%g" /home/build/build) + if [[ "\${uid}" != "\$(id -u)" && "\${gid}" != "\$(id -g)" ]]; then + echo "Adjusting build directory ownership to uid/gid \$(id -un):\$(id -gn)" + sudo chown -R build:build /home/build/build + fi +fi + if [[ "\$@" =~ test ]] && [ -f /usr/bin/run-tests.sh ]; then /usr/bin/run-tests.sh "\${@:-bash}" else "\${@:-bash}" fi + +if [[ -v CHANGE_PERMISSIONS ]]; then + if [[ "\${uid}" != "\$(id -u)" && "\${gid}" != "\$(id -g)" ]]; then + echo "Reverting build directory ownership to uid/gid \${uid}:\${gid}" + sudo chown -R \${uid}:\${gid} /home/build/build + fi +fi EOF # now, switch to build user diff --git a/resources/docker-images/docker-build.inc.sh b/resources/docker-images/docker-build.inc.sh index 109d886c5e..e6427a75cb 100644 --- a/resources/docker-images/docker-build.inc.sh +++ b/resources/docker-images/docker-build.inc.sh @@ -87,7 +87,9 @@ setup_docker() { if [[ "${MSYSTEM:-}" == "MINGW64" ]]; then DOCKER_RUN_ARGS+=(--env DOCKER_RUN_AS_ROOT=1) fi - if ! builder_is_running_on_gha ; then + if builder_is_running_on_gha ; then + DOCKER_RUN_ARGS+=(--env CHANGE_PERMISSIONS=1) + else DOCKER_RUN_ARGS+=(-t) fi diff --git a/resources/docker-images/linux/Dockerfile b/resources/docker-images/linux/Dockerfile index 9bf02375d2..084b0f16c7 100644 --- a/resources/docker-images/linux/Dockerfile +++ b/resources/docker-images/linux/Dockerfile @@ -42,11 +42,28 @@ COPY run-tests.sh /usr/bin/run-tests.sh # Finish bashwrapper script and adjust permissions RUN <> /usr/bin/bashwrapper +if [[ -v CHANGE_PERMISSIONS ]]; then + uid=\$(stat -c "%u" /home/build/build) + gid=\$(stat -c "%g" /home/build/build) + + if [[ "\${uid}" != "\$(id -u)" && "\${gid}" != "\$(id -g)" ]]; then + echo "Adjusting build directory ownership to uid/gid \$(id -un):\$(id -gn)" + sudo chown -R build:build /home/build/build + fi +fi + if [[ "\$@" =~ test ]] && [ -f /usr/bin/run-tests.sh ]; then /usr/bin/run-tests.sh "\${@:-bash}" else "\${@:-bash}" fi + +if [[ -v CHANGE_PERMISSIONS ]]; then + if [[ "\${uid}" != "\$(id -u)" && "\${gid}" != "\$(id -g)" ]]; then + echo "Reverting build directory ownership to uid/gid \${uid}:\${gid}" + sudo chown -R \${uid}:\${gid} /home/build/build + fi +fi EOF # now, switch to build user diff --git a/resources/docker-images/run.sh b/resources/docker-images/run.sh index 1c51600386..534e84eebf 100755 --- a/resources/docker-images/run.sh +++ b/resources/docker-images/run.sh @@ -51,7 +51,7 @@ run_android() { } run_core() { - docker_wrapper run "${DOCKER_RUN_ARGS[@]}" --privileged -i --rm -v "${KEYMAN_ROOT}":/home/build/build \ + docker_wrapper run "${DOCKER_RUN_ARGS[@]}" -i --rm -v "${KEYMAN_ROOT}":/home/build/build \ -v "${KEYMAN_ROOT}/core/build/docker-core/${build_dir}":/home/build/build/core/build \ "${registry_slash}keymanapp/keyman-core-ci:${image_version}" \ "${builder_extra_params[@]}" diff --git a/resources/docker-images/web/Dockerfile b/resources/docker-images/web/Dockerfile index a59f9869b1..fddc8a18b4 100644 --- a/resources/docker-images/web/Dockerfile +++ b/resources/docker-images/web/Dockerfile @@ -58,11 +58,24 @@ RUN curl https://packages.mozilla.org/apt/repo-signing-key.gpg > /etc/apt/keyrin # Finish bashwrapper script and adjust permissions RUN <> /usr/bin/bashwrapper +uid=\$(stat -c "%u" /home/build/build) +gid=\$(stat -c "%g" /home/build/build) + +if [[ "\${uid}" != "\$(id -u)" || "\${gid}" != "\$(id -g)" ]]; then + echo "Adjusting build directory ownership to uid/gid \$(id -un):\$(id -gn)" + sudo chown -R build:build /home/build/build +fi + if [[ "\$@" =~ test ]] && [ -f /usr/bin/run-tests.sh ]; then /usr/bin/run-tests.sh "\${@:-bash}" else "\${@:-bash}" fi + +if [[ "\${uid}" != "\$(id -u)" || "\${gid}" != "\$(id -g)" ]]; then + echo "Reverting build directory ownership to uid/gid \${uid}:\${gid}" + sudo chown -R \${uid}:\${gid} /home/build/build +fi EOF # now, switch to build user diff --git a/resources/teamcity/developer/keyman-developer-release.sh b/resources/teamcity/developer/keyman-developer-release.sh index b24978de0d..7bf2e02553 100755 --- a/resources/teamcity/developer/keyman-developer-release.sh +++ b/resources/teamcity/developer/keyman-developer-release.sh @@ -41,7 +41,7 @@ cd "${KEYMAN_ROOT}/developer/src" function _build_developer() { builder_echo start "build developer" "Building Keyman Developer" - ./build.sh configure build test api publish --npm-publish + ./build.sh configure build test api publish builder_echo end "build developer" success "Finished building Keyman Developer" } diff --git a/resources/teamcity/developer/keyman-developer-test-windows.sh b/resources/teamcity/developer/keyman-developer-test-windows.sh index 668e7a9c04..5bd7961c46 100755 --- a/resources/teamcity/developer/keyman-developer-test-windows.sh +++ b/resources/teamcity/developer/keyman-developer-test-windows.sh @@ -55,12 +55,12 @@ function _build_testkeyboards() { } function publish_sentry_action() { - builder_echo start "publish" "Dry-run publish and api" - ./build.sh api publish --dry-run - builder_echo end "publish" "Dry-run publish and api" + builder_echo start "publish" "publish modules locally and prep api" + ./build.sh api publish + builder_echo end "publish" "publish modules locally and prep api" builder_echo start "publish sentry" "Publishing debug information files to Sentry" - # TODO: move this into build.sh publish? re-scope --dry-run into build.sh? + # TODO: move this into build.sh publish? "${KEYMAN_ROOT}/developer/src/tools/sentry-upload-difs.sh" builder_echo end "publish sentry" success "Finished publishing debug information files to Sentry" } diff --git a/web/src/app/browser/src/contextManager.ts b/web/src/app/browser/src/contextManager.ts index d079ea6d9d..a7c3708a26 100644 --- a/web/src/app/browser/src/contextManager.ts +++ b/web/src/app/browser/src/contextManager.ts @@ -42,7 +42,7 @@ function _SetTargDir(Ptarg: HTMLElement, activeKeyboard: Keyboard) { } } -export default class ContextManager extends ContextManagerBase { +export class ContextManager extends ContextManagerBase { private _activeKeyboard: {keyboard: JSKeyboard, metadata: KeyboardStub}; private cookieManager = new CookieSerializer('KeymanWeb_Keyboard'); readonly focusAssistant = new FocusAssistant(() => this.activeTarget?.isForcingScroll()); diff --git a/web/src/app/browser/src/defaultBrowserRules.ts b/web/src/app/browser/src/defaultBrowserRules.ts index f85baac16d..d6740978d6 100644 --- a/web/src/app/browser/src/defaultBrowserRules.ts +++ b/web/src/app/browser/src/defaultBrowserRules.ts @@ -6,7 +6,7 @@ import { type TextStore } from 'keyman/engine/keyboard'; -import ContextManager from './contextManager.js'; +import { ContextManager } from './contextManager.js'; export default class DefaultBrowserRules extends DefaultRules { private contextManager: ContextManager; diff --git a/web/src/app/browser/src/hardwareEventKeyboard.ts b/web/src/app/browser/src/hardwareEventKeyboard.ts index 1ce8893744..4db23cc0d5 100644 --- a/web/src/app/browser/src/hardwareEventKeyboard.ts +++ b/web/src/app/browser/src/hardwareEventKeyboard.ts @@ -7,7 +7,7 @@ import { DomEventTracker } from 'keyman/engine/events'; import { DesignIFrameElementTextStore, nestedInstanceOf } from 'keyman/engine/element-text-stores'; import { textStoreForEvent, textStoreForElement } from 'keyman/engine/attachment'; -import ContextManager from './contextManager.js'; +import { ContextManager } from './contextManager.js'; type KeyboardState = { activeKeyboard: JSKeyboard, diff --git a/web/src/app/browser/src/keyboardInterface.ts b/web/src/app/browser/src/keyboardInterface.ts index ded3a1d71c..dc9a8cbe80 100644 --- a/web/src/app/browser/src/keyboardInterface.ts +++ b/web/src/app/browser/src/keyboardInterface.ts @@ -2,7 +2,7 @@ import { type AbstractElementTextStore } from 'keyman/engine/element-text-stores import { FloatingOSKView } from 'keyman/engine/osk'; import { KeyboardInterfaceBase } from 'keyman/engine/main'; -import ContextManager from './contextManager.js'; +import { ContextManager } from './contextManager.js'; import { KeymanEngine } from './keymanEngine.js'; export class KeyboardInterface extends KeyboardInterfaceBase { diff --git a/web/src/app/browser/src/keymanEngine.ts b/web/src/app/browser/src/keymanEngine.ts index 1479f9be79..a2a3eab486 100644 --- a/web/src/app/browser/src/keymanEngine.ts +++ b/web/src/app/browser/src/keymanEngine.ts @@ -12,7 +12,7 @@ import KeyboardObject = KeymanWebKeyboard.KeyboardObject; import * as views from './viewsAnchorpoint.js'; import { BrowserConfiguration, BrowserInitOptionDefaults, BrowserInitOptionSpec } from './configuration.js'; -import { default as ContextManager } from './contextManager.js'; +import { ContextManager } from './contextManager.js'; import DefaultBrowserRules from './defaultBrowserRules.js'; import HardwareEventKeyboard from './hardwareEventKeyboard.js'; import { FocusStateAPIObject } from './context/focusAssistant.js'; @@ -443,7 +443,7 @@ export class KeymanEngine extends KeymanEngineBase { +export class ContextManager extends ContextManagerBase { // Change of context? Just replace the SyntheticTextStore. Context will be ENTIRELY controlled // by whatever is hosting the WebView. (Some aspects of this context replacement have // yet to be modularized at this time, though.) diff --git a/web/src/app/webview/src/keymanEngine.ts b/web/src/app/webview/src/keymanEngine.ts index e7d98ee987..14b63dcc51 100644 --- a/web/src/app/webview/src/keymanEngine.ts +++ b/web/src/app/webview/src/keymanEngine.ts @@ -5,7 +5,7 @@ import { getAbsoluteX, getAbsoluteY } from 'keyman/engine/dom-utils'; import { toPrefixedKeyboardId, toUnprefixedKeyboardId } from 'keyman/engine/keyboard-storage'; import { WebviewConfiguration, WebviewInitOptionDefaults, WebviewInitOptionSpec } from './configuration.js'; -import ContextManager, { HostTextStore } from './contextManager.js'; +import { ContextManager, HostTextStore } from './contextManager.js'; import PassthroughKeyboard from './passthroughKeyboard.js'; import { buildEmbeddedGestureConfig, setupEmbeddedListeners } from './oskConfiguration.js'; import { WorkerFactory } from '@keymanapp/lexical-model-layer'; diff --git a/web/src/engine/element-text-stores/abstractElementTextStore.ts b/web/src/engine/element-text-stores/abstractElementTextStore.ts deleted file mode 100644 index e22d6588ae..0000000000 --- a/web/src/engine/element-text-stores/abstractElementTextStore.ts +++ /dev/null @@ -1,52 +0,0 @@ -import { TextStore } from "keyman/engine/keyboard"; -import { EventEmitter } from 'eventemitter3'; - -export abstract class AbstractElementTextStore extends TextStore { - // JS/TS can't do true multiple inheritance, so we maintain class events on a readonly field. - public readonly events: EventEmitter = new EventEmitter(); - - /** - * A field that may be used to track whether or not the represented context has changed over an - * arbitrary period of time. - */ - public changed = false; - - /** - * Returns the underlying element / document modeled by the wrapper. - */ - abstract getElement(): HTMLElement; - - public focus(): void { - const ele = this.getElement(); - if(ele.focus) { - ele.focus(); - } - } - - /** - * Denotes when the represented element is forcing a text scroll via focus manipulation. - * As the intent is not to change the focused element, but just to have the browser update - * the scroll location, standard focus handlers (for updating the active context) should - * not deactivate the element while this state is active. - */ - isForcingScroll(): boolean { - return false; - } - - /** - * A helper method for doInputEvent; creates a simple common event and default dispatching. - * @param elem - */ - protected dispatchInputEventOn(elem: HTMLElement) { - let event: InputEvent; - - // `undefined` in pre-Chrome Edge and Chrome for Android before version 60. - if(window['InputEvent']) { // can't condition on the type directly; TS optimizes that out. - event = new InputEvent('input', {"bubbles": true, "cancelable": false}); - } - - if(elem && event) { - elem.dispatchEvent(event); - } - } -} \ No newline at end of file diff --git a/web/src/engine/element-text-stores/contentEditableElementTextStore.ts b/web/src/engine/element-text-stores/contentEditableElementTextStore.ts deleted file mode 100644 index 0a42117402..0000000000 --- a/web/src/engine/element-text-stores/contentEditableElementTextStore.ts +++ /dev/null @@ -1,273 +0,0 @@ -import { AbstractElementTextStore } from './abstractElementTextStore.js'; -import { KMWString } from 'keyman/common/web-utils'; - -class SelectionCaret { - node: Node; - offset: number; - - constructor(node: Node, offset: number) { - this.node = node; - this.offset = offset; - } -} - -class SelectionRange { - start: SelectionCaret; - end: SelectionCaret; - - constructor(start: SelectionCaret, end: SelectionCaret) { - this.start = start; - this.end = end; - } -} - -export class ContentEditableElementTextStore extends AbstractElementTextStore<{}> { - root: HTMLElement; - - constructor(ele: HTMLElement) { - if(ele.isContentEditable) { - super(); - this.root = ele; - } else { - throw "Specified element is not already content-editable!"; - } - } - - get isSynthetic(): boolean { - return false; - } - - getElement(): HTMLElement { - return this.root; - } - - isSelectionEmpty(): boolean { - if(!this.hasSelection()) { - return true; - } - - return this.root.ownerDocument.getSelection().isCollapsed; - } - - hasSelection(): boolean { - const Lsel = this.root.ownerDocument.getSelection(); - - if(this.root != Lsel.anchorNode && !this.root.contains(Lsel.anchorNode)) { - return false; - } - - if(this.root != Lsel.focusNode && !this.root.contains(Lsel.focusNode)) { - return false; - } - - return true; - } - - clearSelection(): void { - if(this.hasSelection()) { - const Lsel = this.root.ownerDocument.getSelection(); - - if(!Lsel.isCollapsed) { - Lsel.deleteFromDocument(); // I2134, I2192 - } - } else { - console.warn("Attempted to clear an unowned Selection!"); - } - } - - invalidateSelection(): void { /* No cache maintenance needed here, partly because - * it's impossible to cache a Selection; it mutates. - */ } - - getCarets(): SelectionRange { - const Lsel = this.root.ownerDocument.getSelection(); - let code = Lsel.anchorNode.compareDocumentPosition(Lsel.focusNode); - - if(Lsel.isCollapsed) { - const caret = new SelectionCaret(Lsel.anchorNode, Lsel.anchorOffset); - return new SelectionRange(caret, caret); - } else { - const anchor = new SelectionCaret(Lsel.anchorNode, Lsel.anchorOffset); - const focus = new SelectionCaret(Lsel.focusNode, Lsel.focusOffset); - - if(anchor.node == focus.node) { - code = (focus.offset - anchor.offset > 0) ? 2 : 4; - } - - if(code & 2) { - return new SelectionRange(anchor, focus); - } else { // Default - // can test against code & 4 to ensure Focus is before anchor, though. - return new SelectionRange(focus, anchor); - } - } - } - - getDeadkeyCaret(): number { - return KMWString.length(this.getTextBeforeCaret()); - } - - getTextBeforeCaret(): string { - if(!this.hasSelection()) { - return this.getText(); - } - - const caret = this.getCarets().start; - - if(caret.node.nodeType != 3) { - return ''; // Must be a text node to provide a context. - } - - return caret.node.textContent.substr(0, caret.offset); - } - - getSelectedText(): string { - // TODO: figure out the proper implementation. - // KMW 16 and before behavior may be maintained by just returning the empty string. - return ''; - } - - getTextAfterCaret(): string { - if(!this.hasSelection()) { - return ''; - } - - const caret = this.getCarets().end; - - if(caret.node.nodeType != 3) { - return ''; // Must be a text node to provide a context. - } - - return caret.node.textContent.substr(caret.offset); - } - - getText(): string { - return this.root.innerText; - } - - deleteCharsBeforeCaret(dn: number) { - if(!this.hasSelection() || dn <= 0) { - return; - } - - const start = this.getCarets().start; - - // Bounds-check on the number of chars to delete. - if(dn > start.offset) { - dn = start.offset; - } - - if(start.node.nodeType != 3) { - console.warn("Deletion of characters requested without available context!"); - return; // No context to delete characters from. - } - - const range = this.root.ownerDocument.createRange(); - const dnOffset = start.offset - KMWString.substr(start.node.nodeValue.substr(0, start.offset), -dn).length; - - range.setStart(start.node, dnOffset); - range.setEnd(start.node, start.offset); - - this.adjustDeadkeys(-dn); - range.deleteContents(); - // No need to reposition the caret - the DOM will auto-move the selection accordingly, since - // we didn't use the selection to delete anything. - } - - insertTextBeforeCaret(s: string) { - if(!this.hasSelection()) { - return; - } - - const start = this.getCarets().start; - const delta = KMWString.length(s); - const Lsel = this.root.ownerDocument.getSelection(); - - if(delta == 0) { - return; - } - - this.adjustDeadkeys(delta); - - // While Selection.extend() was really nice for this, IE didn't support it whatsoever. - // However, IE (11, at least) DID support setting selections via ranges, so we were still - // able to manage the caret properly. - // - // TODO: double-check that it was only IE-motivated, re-implement with Selection.extend(). - const finalCaret = this.root.ownerDocument.createRange(); - - if(start.node.nodeType == 3) { - const textStart = start.node; - textStart.insertData(start.offset, s); - finalCaret.setStart(textStart, start.offset + s.length); - } else { - // Create a new text node - empty control - const n = start.node.ownerDocument.createTextNode(s); - - const range = this.root.ownerDocument.createRange(); - range.setStart(start.node, start.offset); - range.collapse(true); - range.insertNode(n); - finalCaret.setStart(n, s.length); - } - - finalCaret.collapse(true); - Lsel.removeAllRanges(); - try { - Lsel.addRange(finalCaret); - } catch(e) { - // Chrome (through 4.0 at least) throws an exception because it has not synchronised its content with the selection. - // scrollIntoView synchronises the content for selection - start.node.parentElement.scrollIntoView(); - Lsel.addRange(finalCaret); - } - Lsel.collapseToEnd(); - } - - handleNewlineAtCaret(): void { - // TODO: Implement. - // - // As it turns out, we never had an implementation for handling newline inputs from the OSK for this element type. - // At least this way, it's more explicit. - // - // Note: consult "// Create a new text node - empty control" case in insertTextBeforeCaret - - // this helps to handle the browser-default implementation of newline handling. In particular, - // entry of the first character after a newline. - // - // If raw newlines are entered into the HTML, but as with usual HTML, they're interpreted as excess whitespace and - // have no effect. We need to add DOM elements for a functional newline. - } - - protected setTextAfterCaret(s: string) { - if(!this.hasSelection()) { - return; - } - - const caret = this.getCarets().end; - const delta = KMWString.length(s); - - if(delta == 0) { - return; - } - - // This is designed explicitly for use in direct-setting operations; deadkeys - // will be handled after this method. - - if(caret.node.nodeType == 3) { - const textStart = caret.node; - textStart.replaceData(caret.offset, textStart.length, s); - } else { - // Create a new text node - empty control - const n = caret.node.ownerDocument.createTextNode(s); - - const range = this.root.ownerDocument.createRange(); - range.setStart(caret.node, caret.offset); - range.collapse(true); - range.insertNode(n); - } - } - - doInputEvent() { - this.dispatchInputEventOn(this.root); - } -} \ No newline at end of file diff --git a/web/src/engine/element-text-stores/createTextStoreForElement.ts b/web/src/engine/element-text-stores/createTextStoreForElement.ts deleted file mode 100644 index a591ae32f9..0000000000 --- a/web/src/engine/element-text-stores/createTextStoreForElement.ts +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Keyman is copyright (C) SIL Global. MIT License. - */ - -import { type AbstractElementTextStore } from './abstractElementTextStore.js'; -import { InputElementTextStore } from './inputElementTextStore.js'; -import { TextAreaElementTextStore } from './textAreaElementTextStore.js'; -import { DesignIFrameElementTextStore } from './designIFrameElementTextStore.js'; -import { ContentEditableElementTextStore } from './contentEditableElementTextStore.js'; -import { nestedInstanceOf } from './utils.js'; - -/** - * Wraps an HTMLElement in a concrete text-store implementation. - * - * @param e - The HTMLElement to create a text-store for. - * @returns A concrete AbstractElementTextStore for the element, or null if the element - * type is not supported or no suitable store can be created. - */ -export function createTextStoreForElement(e: HTMLElement): AbstractElementTextStore { - // Complex type scoping is implemented here so that kmwutils.ts is not a dependency for test compilations. - - if(nestedInstanceOf(e, "HTMLInputElement")) { - return new InputElementTextStore( e); - } else if(nestedInstanceOf(e, "HTMLTextAreaElement")) { - return new TextAreaElementTextStore( e); - } else if(nestedInstanceOf(e, "HTMLIFrameElement")) { - const iframe = e; - - if(iframe.contentWindow && iframe.contentWindow.document && iframe.contentWindow.document.designMode == "on") { - return new DesignIFrameElementTextStore(iframe); - } else if (e.isContentEditable) { - // Do content-editable