Feature: Fetch ArgyllCMS release binaries at build time and offer USB driver install on Windows #127

Closed
opened 2026-08-28 23:15:08 +01:00 by gronod · 0 comments
Owner

Repo: gronod/ICCery (GitHub mirror: Gronod/ICCery)
Related: Gronod/argyllcms binary releases
Type: Build / packaging
Priority: High (unblocks macOS packages, shrinks the git repo, required for instrument USB on Windows)


Summary

Stop committing ArgyllCMS binaries into ICCery. At package-build time, download the latest (or pinned) binary release archives from https://github.com/Gronod/argyllcms/releases, extract them, and bundle only the current platform’s tools into the Tauri resources.

On Windows, also bundle the ArgyllCMS USB instrument driver tree from that same archive, and have the NSIS installer offer to run ArgyllCMS_install_USB.exe as an option at install time.

Also fix the existing Windows CI sidecar check, which looks for the wrong filename (argyll-instlist.exe instead of instlist.exe).


Background / current state

Vendored binaries (to be removed from git)

Path Approx. size Notes
src-tauri/argyll/linux-x86_64/ ~245 MB Full Linux toolset + three .mock files
src-tauri/argyll/windows-x86_64/ ~130 MB Full Windows .exe set
src-tauri/argyll/reference_gamuts/sRGB.gam 262 B Keep in git. Not part of the Argyll binary archive. Frontend actually loads src/assets/sRGB.gam.

Runtime lookup is in src-tauri/src/commands.rs (resolve_binary):

argyll/{linux-x86_64,windows-x86_64,macos-x86_64,macos-aarch64}/<tool>[.exe]

macOS dirs are already expected by Rust and by the macOS workflows, but they are not in the repo. Fetching the macOS archives is what makes those jobs real.

tauri.conf.json already bundles everything under argyll/:

"resources": ["argyll/**/*"]

Do not switch to Tauri externalBin. That is one sidecar per target triple, not a directory of ~50 tools.

CI today

Workflows exist in both .github/workflows/ and .gitea/workflows/:

  • build-windows.yml
  • build-linux.yml
  • build-macos.yml

They currently:

  1. Warn (do not fail) if sidecars are missing.
  2. Delete the other OS’s binary tree so it is not bundled.
  3. Assume binaries were committed.

Bug: wrong sidecar filename (must fix)

Windows workflows check a file that does not exist:

# .github/workflows/build-windows.yml  AND  .gitea/workflows/build-windows.yml
if (!(Test-Path "src-tauri\argyll\windows-x86_64\argyll-instlist.exe")) {
    Write-Host "Warning: Windows ArgyllCMS binaries not found. ..."
}

The real binary is instlist.exe (Linux/macOS: instlist). There is no argyll- prefix on any sidecar.

This check is a no-op today: it always warns, never fails, and never blocked a release. When fetch is added, the verify step must test instlist.exe / instlist and must fail the job if it is missing.

Upstream release assets (source of truth)

Latest at time of writing: v3.5.0-ICCery.1.1

Asset suffix to match Dest in ICCery
*_linux_x86_64_bin.tgz src-tauri/argyll/linux-x86_64/
*_win64_exe.zip src-tauri/argyll/windows-x86_64/ and src-tauri/argyll/usb/
*_macOS_x86_64_bin.tgz src-tauri/argyll/macos-x86_64/
*_macOS_arm64_bin.tgz src-tauri/argyll/macos-aarch64/

Filenames include a tag and short SHA, e.g. Argyll_v3.5.0-ICCery.1.1_b02df94_win64_exe.zip. Match by suffix, never hardcode the SHA or full name.

Windows zip layout (verified)

Do not hardcode the top-level folder name. makepackagebin.sh uses ARGYLL_VERSION_STR from h/aconfig.h, which is still 3.5.0, so the folder is Argyll_V3.5.0/ even when the GitHub tag is v3.5.0-ICCery.1.1. Discover the root at extract time.

Argyll_V3.5.0/bin/*.exe                         → src-tauri/argyll/windows-x86_64/
Argyll_V3.5.0/License.txt                       → copy next to the binaries (AGPL)
Argyll_V3.5.0/usb/ArgyllCMS_install_USB.exe     → src-tauri/argyll/usb/
Argyll_V3.5.0/usb/ArgyllCMS_uninstall_USB.exe
Argyll_V3.5.0/usb/ArgyllCMS.inf
Argyll_V3.5.0/usb/ArgyllCMS.cat
Argyll_V3.5.0/usb/ArgyllCMS_x64.cat
Argyll_V3.5.0/usb/ArgyllCMS_arm64.cat
Argyll_V3.5.0/usb/bin/libusb-win32-bin-README.txt
Argyll_V3.5.0/usb/bin/x86/libusb0.sys
Argyll_V3.5.0/usb/bin/amd64/libusb0.sys
Argyll_V3.5.0/usb/bin/arm64/libusb0.sys

ArgyllCMS_install_USB.exe is a GUI libusb-win32 installer. Jam copies it to usb/ (from usb/bin/amd64/ on x64). It must be launched with the inf/cat/sys tree beside it. Do not run it silently.

Linux/macOS tarballs use the same Argyll_V*/bin/ layout (no .exe). Linux also ships udev rules under usb/do not copy Linux usb/ into the ICCery resource tree; ICCery only needs the Windows USB driver installer option.

Linux .mock files (chartread.mock, colprof.mock, profcheck.mock) live in the vendored Linux dir today and are not in the Argyll archive. Nothing in the app references them. Move to src-tauri/argyll/mocks/ or delete them. Do not leave them inside a directory the fetch script wipes.


Goals

  1. ICCery git no longer contains ArgyllCMS executables.
  2. npm run fetch-argyll downloads the latest Gronod/argyllcms binary release for the current OS/arch (or a pinned tag) and stages it under src-tauri/argyll/.
  3. Linux, Windows, and macOS package CI fetch before tauri build and fail if sidecars are missing.
  4. Windows NSIS installer bundles the USB driver tree and offers to run ArgyllCMS_install_USB.exe at install time.
  5. Windows CI sidecar check uses instlist.exe and is a hard failure.

Non-goals:

  • Rewriting git history to purge old binaries (optional follow-up).
  • Changing how resolve_binary finds tools (path layout stays the same).
  • Auto-installing Linux udev rules or macOS kexts.
  • Building ArgyllCMS from source inside the ICCery CI.

Implementation

1. Fetch script

New file: scripts/fetch-argyll.mjs

Node ESM so it runs on Gitea runners, GitHub runners, and local machines with the existing Node 20 toolchain. No extra npm dependencies.

CLI

node scripts/fetch-argyll.mjs [--force] [--platform <id>]
Flag / env Behaviour
--force Re-download even if dest already has instlist / instlist.exe
--platform One of linux-x86_64, windows-x86_64, macos-x86_64, macos-aarch64. Default: detect from process.platform + process.arch
ARGYLL_RELEASE_TAG If set (e.g. v3.5.0-ICCery.1.1), fetch that release. Else GET .../releases/latest
GITHUB_TOKEN Optional. Send as Authorization: Bearer to raise API rate limits. Public repo works unauthenticated.

API

GET https://api.github.com/repos/Gronod/argyllcms/releases/latest
GET https://api.github.com/repos/Gronod/argyllcms/releases/tags/${ARGYLL_RELEASE_TAG}

User-Agent required (ICCery-fetch-argyll). Accept application/vnd.github+json.

Asset selection

--platform Asset name must end with
linux-x86_64 _linux_x86_64_bin.tgz
windows-x86_64 _win64_exe.zip
macos-x86_64 _macOS_x86_64_bin.tgz
macos-aarch64 _macOS_arm64_bin.tgz

Download only the current platform. The Linux tarball is ~100 MB; do not pull all four.

Extract and stage

  1. Download to a temp dir.
  2. Extract (.zip via unzip / PowerShell Expand-Archive / Node; .tgz via tar).
  3. Find the archive root: the unique top-level Argyll_V* directory. Fail if missing or if bin/ is missing inside it.
  4. Replace dest contents:
    • linux-x86_64 / macos-*: copy bin/*src-tauri/argyll/<platform>/
    • windows-x86_64: copy bin/*src-tauri/argyll/windows-x86_64/ and copy the entire usb/ tree → src-tauri/argyll/usb/
  5. Copy License.txt from the archive root into the platform dest (AGPL).
  6. Do not touch src-tauri/argyll/reference_gamuts/ or src-tauri/argyll/mocks/.
  7. Skip work if dest already contains instlist / instlist.exe unless --force.
  8. Fail hard (non-zero exit) if:
    • API/asset/download/extract fails
    • bin/ is empty
    • Windows: usb/ArgyllCMS_install_USB.exe is missing after staging
    • instlist / instlist.exe is missing after staging

Cache: skip when the marker binary exists. CI always passes --force.

package.json

"scripts": {
  "fetch-argyll": "node scripts/fetch-argyll.mjs",
  "tauri": "tauri"
}

Do not auto-run fetch on every tauri invocation; local tauri dev should use a previously fetched tree. Document npm run fetch-argyll as a prerequisite.

src-tauri/build.rs

Do not download from build.rs (no network in some environments; breaks Cargo incremental). If instlist / instlist.exe is missing for this OS, panic! with:

ArgyllCMS sidecars not found. Run `npm run fetch-argyll` from the repo root before `tauri build` / `tauri dev`.

2. Stop committing binaries

.gitignore — add:

src-tauri/argyll/linux-x86_64/
src-tauri/argyll/windows-x86_64/
src-tauri/argyll/macos-x86_64/
src-tauri/argyll/macos-aarch64/
src-tauri/argyll/usb/

Keep src-tauri/argyll/reference_gamuts/ tracked.

Remove from the index (leave git history as-is):

git rm -r --cached src-tauri/argyll/linux-x86_64 src-tauri/argyll/windows-x86_64

Mocks: move chartread.mock, colprof.mock, profcheck.mock to src-tauri/argyll/mocks/ or delete them. They must not live under a gitignored platform dir.


3. CI — fetch, then fail if sidecars are missing

Update all six workflow files (GitHub + Gitea, three platforms).

Replace “Check sidecar binaries” and “Prepare platform-specific resources” with a fetch + hard verify. The “delete the other OS’s binaries” step becomes unnecessary (they will not be present) and should be removed.

Place fetch after npm ci (the script is invoked via npm run fetch-argyll).

Linux (.github/workflows/build-linux.yml and .gitea/workflows/build-linux.yml)

Remove:

- name: Prepare platform-specific resources
  run: |
    echo "Removing Windows ArgyllCMS binaries..."
    rm -rf src-tauri/argyll/windows-x86_64

Add (after npm ci):

- name: Fetch ArgyllCMS binaries
  env:
    ARGYLL_RELEASE_TAG: ${{ vars.ARGYLL_RELEASE_TAG }}
    GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
  run: npm run fetch-argyll -- --force --platform linux-x86_64

- name: Verify sidecar binaries
  run: |
    test -x src-tauri/argyll/linux-x86_64/instlist
    test -x src-tauri/argyll/linux-x86_64/targen
    test -x src-tauri/argyll/linux-x86_64/chartread
    test -x src-tauri/argyll/linux-x86_64/colprof

Windows (.github/workflows/build-windows.yml and .gitea/workflows/build-windows.yml)

This is the instlist fix. Delete the current warning-only step that tests argyll-instlist.exe. Replace with:

- name: Fetch ArgyllCMS binaries
  shell: powershell
  env:
    ARGYLL_RELEASE_TAG: ${{ vars.ARGYLL_RELEASE_TAG }}
    GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
  run: npm run fetch-argyll -- --force --platform windows-x86_64

- name: Verify sidecar binaries
  shell: powershell
  run: |
    $required = @(
      "src-tauri\argyll\windows-x86_64\instlist.exe",
      "src-tauri\argyll\windows-x86_64\targen.exe",
      "src-tauri\argyll\windows-x86_64\chartread.exe",
      "src-tauri\argyll\windows-x86_64\colprof.exe",
      "src-tauri\argyll\usb\ArgyllCMS_install_USB.exe",
      "src-tauri\argyll\usb\ArgyllCMS.inf"
    )
    foreach ($p in $required) {
      if (!(Test-Path $p)) { throw "Missing required ArgyllCMS file: $p" }
    }

Also remove the “Prepare platform-specific resources” step that deletes src-tauri\argyll\linux-x86_64.

macOS (.github/workflows/build-macos.yml and .gitea/workflows/build-macos.yml)

The matrix already has binary_dir: macos-x86_64 / macos-aarch64. Replace the warning-only “Check sidecar binaries” step:

- name: Fetch ArgyllCMS binaries
  env:
    ARGYLL_RELEASE_TAG: ${{ vars.ARGYLL_RELEASE_TAG }}
    GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
  run: npm run fetch-argyll -- --force --platform ${{ matrix.platform.binary_dir }}

- name: Verify sidecar binaries
  run: |
    test -x "src-tauri/argyll/${{ matrix.platform.binary_dir }}/instlist"
    test -x "src-tauri/argyll/${{ matrix.platform.binary_dir }}/targen"

vars.ARGYLL_RELEASE_TAG is optional. Empty means “latest”. Set it on the repo if a release must pin a known-good Argyll tag.

Gitea secrets.GITHUB_TOKEN is the Gitea job token; GitHub API still works unauthenticated for this public repo. Passing it is harmless if the host is Gitea (GitHub will ignore a Gitea token). If Gitea rate-limits become an issue, add a GH_API_TOKEN secret for api.github.com.


4. Windows installer — optional USB drivers

Two parts: bundle the files (automatic once fetch stages argyll/usb/**) and offer to run the installer.

src-tauri/tauri.conf.json

Keep "resources": ["argyll/**/*"] — that already picks up argyll/usb/**.

Change the NSIS block:

"windows": {
  "wix": {
    "bannerPath": "icons/wix-banner.bmp",
    "dialogImagePath": "icons/wix-dialog.bmp"
  },
  "nsis": {
    "installMode": "both",
    "installerIcon": "icons/icon.ico",
    "headerImage": "icons/nsis-header.bmp",
    "sidebarImage": "icons/nsis-sidebar.bmp",
    "installerHooks": "windows/hooks.nsh"
  }
}

installMode: "both" is required. USB driver install needs admin; default Tauri NSIS is current-user and the driver installer will fail or UAC-loop. Keep current-user as a choice; only prompt for USB when the NSIS run is elevated.

New file: src-tauri/windows/hooks.nsh

Tauri v2 NSIS hooks are NSIS_HOOK_PREINSTALL, NSIS_HOOK_POSTINSTALL, NSIS_HOOK_PREUNINSTALL, NSIS_HOOK_POSTUNINSTALL. There is no custom MUI page hook without forking the NSIS template. A Yes/No at install time is the intended UX.

Var InstallArgyllUSB

!macro NSIS_HOOK_PREINSTALL
  StrCpy $InstallArgyllUSB 0
  ${If} ${IsUserAdmin}
    MessageBox MB_YESNO|MB_ICONQUESTION \
      "Install ArgyllCMS USB instrument drivers?$\r$\n$\r$\nRequired for spectrophotometers (i1Pro, ColorMunki, SpyderPrint, etc.)." \
      IDNO skip_usb_prompt
    StrCpy $InstallArgyllUSB 1
    skip_usb_prompt:
  ${EndIf}
!macroend

!macro NSIS_HOOK_POSTINSTALL
  ${If} $InstallArgyllUSB == 1
    ; Confirm this path with one NSIS build. Tauri v2 typically places
    ; bundle.resources next to the exe, so:
    ;   $INSTDIR\argyll\usb\ArgyllCMS_install_USB.exe
    ; If the first build puts them under $INSTDIR\resources\..., update this line.
    IfFileExists "$INSTDIR\argyll\usb\ArgyllCMS_install_USB.exe" 0 usb_missing
      ExecWait '"$INSTDIR\argyll\usb\ArgyllCMS_install_USB.exe"'
      Goto usb_done
    usb_missing:
      MessageBox MB_ICONEXCLAMATION "ArgyllCMS USB driver installer was not found in the package."
    usb_done:
  ${EndIf}
!macroend

!macro NSIS_HOOK_PREUNINSTALL
!macroend

!macro NSIS_HOOK_POSTUNINSTALL
  ; Do not auto-run ArgyllCMS_uninstall_USB.exe. Driver removal is a
  ; separate admin action and can break other Argyll-based apps.
!macroend

Rules:

  • Do not run the USB installer silently. It has its own GUI and needs the inf/sys/cat tree next to it.
  • Do not prompt when the installer is not elevated.
  • After the first NSIS build, confirm the on-disk path ($INSTDIR\argyll\usb\... vs $INSTDIR\resources\argyll\usb\...) and fix ExecWait if needed.
  • ${IsUserAdmin} requires LogicLib.nsh / UserInfo — the stock Tauri NSIS template already includes LogicLib. If the hook fails to compile, add !include "LogicLib.nsh" at the top of hooks.nsh (only if the template does not already include it).

MSI / WiX

WiX has no NSIS-style hook. Out of scope for the first cut unless cheap:

  • Minimum: USB files are still inside the MSI via argyll/**/*. Add a Start Menu shortcut “Install USB instrument drivers” pointing at argyll\usb\ArgyllCMS_install_USB.exe.
  • Full parity: WiX fragment with an optional Feature + CustomAction. Not required for this ticket.

NSIS (.exe) is the installer that must prompt at install time.


5. Docs

README.md — Building from Source

Add before npm run tauri dev:

# Download ArgyllCMS sidecars for this OS (from github.com/Gronod/argyllcms/releases)
npm run fetch-argyll

Note:

  • Windows NSIS setup offers an optional “Install ArgyllCMS USB instrument drivers” step (admin / per-machine).
  • Override the Argyll release with ARGYLL_RELEASE_TAG=vX.Y.Z npm run fetch-argyll.
  • Sidecars are not in git; tauri build / tauri dev will fail until fetch has been run once.

ROADMAP.md

One bullet under the current milestone / packaging: Argyll sidecars fetched from Gronod/argyllcms releases; Windows NSIS USB driver option.

THIRDPARTY-LICENSES.md

Point at the bundled License.txt that ships with the fetched archive (AGPLv3).


File checklist

File Action
scripts/fetch-argyll.mjs Create
package.json Add fetch-argyll script
.gitignore Ignore platform binary dirs + argyll/usb/
src-tauri/argyll/linux-x86_64/ git rm -r --cached
src-tauri/argyll/windows-x86_64/ git rm -r --cached
src-tauri/argyll/mocks/ Move or delete the three .mock files
src-tauri/build.rs Panic if instlist missing
src-tauri/tauri.conf.json nsis.installMode: "both", nsis.installerHooks
src-tauri/windows/hooks.nsh Create
.github/workflows/build-windows.yml Fetch + fail on missing instlist.exe (not argyll-instlist.exe)
.github/workflows/build-linux.yml Fetch + fail on missing instlist
.github/workflows/build-macos.yml Fetch + fail on missing instlist
.gitea/workflows/build-windows.yml Same as GitHub Windows
.gitea/workflows/build-linux.yml Same as GitHub Linux
.gitea/workflows/build-macos.yml Same as GitHub macOS
README.md Fetch prerequisite + USB option
ROADMAP.md Short note
THIRDPARTY-LICENSES.md Bundled Argyll license pointer

No change to resolve_binary path layout unless a fetch dry-run shows a different bin/ shape.


Implementation order

  1. Write scripts/fetch-argyll.mjs. Dry-run on Linux: confirm bin/ lands in src-tauri/argyll/linux-x86_64/ and instlist is executable. Dry-run the Windows zip on any OS with --platform windows-x86_64: confirm instlist.exe and usb/ArgyllCMS_install_USB.exe.
  2. .gitignore + git rm --cached the vendored trees; relocate/drop .mock files.
  3. build.rs missing-sidecar panic.
  4. Wire fetch + hard verify into all six workflows. Windows verify must use instlist.exe.
  5. tauri.conf.json installMode: "both" + windows/hooks.nsh.
  6. One Windows NSIS build: confirm $INSTDIR\...\ArgyllCMS_install_USB.exe exists in the staged installer payload, Yes launches it, No skips it, current-user install does not prompt (or prompts only when admin).
  7. README / ROADMAP / licenses.

Acceptance criteria

  • src-tauri/argyll/linux-x86_64/ and src-tauri/argyll/windows-x86_64/ are not tracked by git. reference_gamuts/ still is.
  • npm run fetch-argyll on Linux populates linux-x86_64/ from https://github.com/Gronod/argyllcms/releases/latest (or ARGYLL_RELEASE_TAG).
  • npm run fetch-argyll -- --platform windows-x86_64 populates windows-x86_64/ and usb/, including ArgyllCMS_install_USB.exe and ArgyllCMS.inf.
  • Fetch of the wrong/missing asset exits non-zero.
  • Linux / Windows / macOS CI (GitHub and Gitea) fetch before tauri build and fail if instlist / `ins
**Repo:** [gronod/ICCery](https://git.i3omb.com/gronod/ICCery) (GitHub mirror: [Gronod/ICCery](https://github.com/Gronod/ICCery)) **Related:** [Gronod/argyllcms](https://github.com/Gronod/argyllcms) binary releases **Type:** Build / packaging **Priority:** High (unblocks macOS packages, shrinks the git repo, required for instrument USB on Windows) --- ## Summary Stop committing ArgyllCMS binaries into ICCery. At package-build time, download the latest (or pinned) binary release archives from `https://github.com/Gronod/argyllcms/releases`, extract them, and bundle only the current platform’s tools into the Tauri resources. On Windows, also bundle the ArgyllCMS USB instrument driver tree from that same archive, and have the NSIS installer offer to run `ArgyllCMS_install_USB.exe` as an option at install time. Also fix the existing Windows CI sidecar check, which looks for the wrong filename (`argyll-instlist.exe` instead of `instlist.exe`). --- ## Background / current state ### Vendored binaries (to be removed from git) | Path | Approx. size | Notes | |---|---|---| | `src-tauri/argyll/linux-x86_64/` | ~245 MB | Full Linux toolset + three `.mock` files | | `src-tauri/argyll/windows-x86_64/` | ~130 MB | Full Windows `.exe` set | | `src-tauri/argyll/reference_gamuts/sRGB.gam` | 262 B | **Keep in git.** Not part of the Argyll binary archive. Frontend actually loads `src/assets/sRGB.gam`. | Runtime lookup is in `src-tauri/src/commands.rs` (`resolve_binary`): ```text argyll/{linux-x86_64,windows-x86_64,macos-x86_64,macos-aarch64}/<tool>[.exe] ``` macOS dirs are already expected by Rust and by the macOS workflows, but they are **not** in the repo. Fetching the macOS archives is what makes those jobs real. `tauri.conf.json` already bundles everything under `argyll/`: ```json "resources": ["argyll/**/*"] ``` Do **not** switch to Tauri `externalBin`. That is one sidecar per target triple, not a directory of ~50 tools. ### CI today Workflows exist in **both** `.github/workflows/` and `.gitea/workflows/`: - `build-windows.yml` - `build-linux.yml` - `build-macos.yml` They currently: 1. Warn (do not fail) if sidecars are missing. 2. Delete the *other* OS’s binary tree so it is not bundled. 3. Assume binaries were committed. ### Bug: wrong sidecar filename (must fix) Windows workflows check a file that does not exist: ```powershell # .github/workflows/build-windows.yml AND .gitea/workflows/build-windows.yml if (!(Test-Path "src-tauri\argyll\windows-x86_64\argyll-instlist.exe")) { Write-Host "Warning: Windows ArgyllCMS binaries not found. ..." } ``` The real binary is `instlist.exe` (Linux/macOS: `instlist`). There is no `argyll-` prefix on any sidecar. This check is a no-op today: it always warns, never fails, and never blocked a release. When fetch is added, the verify step **must** test `instlist.exe` / `instlist` and **must fail the job** if it is missing. ### Upstream release assets (source of truth) Latest at time of writing: [`v3.5.0-ICCery.1.1`](https://github.com/Gronod/argyllcms/releases/tag/v3.5.0-ICCery.1.1) | Asset suffix to match | Dest in ICCery | |---|---| | `*_linux_x86_64_bin.tgz` | `src-tauri/argyll/linux-x86_64/` | | `*_win64_exe.zip` | `src-tauri/argyll/windows-x86_64/` **and** `src-tauri/argyll/usb/` | | `*_macOS_x86_64_bin.tgz` | `src-tauri/argyll/macos-x86_64/` | | `*_macOS_arm64_bin.tgz` | `src-tauri/argyll/macos-aarch64/` | Filenames include a tag and short SHA, e.g. `Argyll_v3.5.0-ICCery.1.1_b02df94_win64_exe.zip`. **Match by suffix, never hardcode the SHA or full name.** ### Windows zip layout (verified) Do **not** hardcode the top-level folder name. `makepackagebin.sh` uses `ARGYLL_VERSION_STR` from `h/aconfig.h`, which is still `3.5.0`, so the folder is `Argyll_V3.5.0/` even when the GitHub tag is `v3.5.0-ICCery.1.1`. Discover the root at extract time. ```text Argyll_V3.5.0/bin/*.exe → src-tauri/argyll/windows-x86_64/ Argyll_V3.5.0/License.txt → copy next to the binaries (AGPL) Argyll_V3.5.0/usb/ArgyllCMS_install_USB.exe → src-tauri/argyll/usb/ Argyll_V3.5.0/usb/ArgyllCMS_uninstall_USB.exe Argyll_V3.5.0/usb/ArgyllCMS.inf Argyll_V3.5.0/usb/ArgyllCMS.cat Argyll_V3.5.0/usb/ArgyllCMS_x64.cat Argyll_V3.5.0/usb/ArgyllCMS_arm64.cat Argyll_V3.5.0/usb/bin/libusb-win32-bin-README.txt Argyll_V3.5.0/usb/bin/x86/libusb0.sys Argyll_V3.5.0/usb/bin/amd64/libusb0.sys Argyll_V3.5.0/usb/bin/arm64/libusb0.sys ``` `ArgyllCMS_install_USB.exe` is a GUI libusb-win32 installer. Jam copies it to `usb/` (from `usb/bin/amd64/` on x64). It **must** be launched with the inf/cat/sys tree beside it. Do not run it silently. Linux/macOS tarballs use the same `Argyll_V*/bin/` layout (no `.exe`). Linux also ships udev rules under `usb/` — **do not** copy Linux `usb/` into the ICCery resource tree; ICCery only needs the Windows USB driver installer option. Linux `.mock` files (`chartread.mock`, `colprof.mock`, `profcheck.mock`) live in the vendored Linux dir today and are **not** in the Argyll archive. Nothing in the app references them. Move to `src-tauri/argyll/mocks/` or delete them. Do not leave them inside a directory the fetch script wipes. --- ## Goals 1. ICCery git no longer contains ArgyllCMS executables. 2. `npm run fetch-argyll` downloads the latest Gronod/argyllcms binary release for the current OS/arch (or a pinned tag) and stages it under `src-tauri/argyll/`. 3. Linux, Windows, and macOS package CI fetch before `tauri build` and fail if sidecars are missing. 4. Windows NSIS installer bundles the USB driver tree and offers to run `ArgyllCMS_install_USB.exe` at install time. 5. Windows CI sidecar check uses `instlist.exe` and is a hard failure. Non-goals: - Rewriting git history to purge old binaries (optional follow-up). - Changing how `resolve_binary` finds tools (path layout stays the same). - Auto-installing Linux udev rules or macOS kexts. - Building ArgyllCMS from source inside the ICCery CI. --- ## Implementation ### 1. Fetch script **New file:** `scripts/fetch-argyll.mjs` Node ESM so it runs on Gitea runners, GitHub runners, and local machines with the existing Node 20 toolchain. No extra npm dependencies. **CLI** ```text node scripts/fetch-argyll.mjs [--force] [--platform <id>] ``` | Flag / env | Behaviour | |---|---| | `--force` | Re-download even if dest already has `instlist` / `instlist.exe` | | `--platform` | One of `linux-x86_64`, `windows-x86_64`, `macos-x86_64`, `macos-aarch64`. Default: detect from `process.platform` + `process.arch` | | `ARGYLL_RELEASE_TAG` | If set (e.g. `v3.5.0-ICCery.1.1`), fetch that release. Else `GET .../releases/latest` | | `GITHUB_TOKEN` | Optional. Send as `Authorization: Bearer` to raise API rate limits. Public repo works unauthenticated. | **API** ```text GET https://api.github.com/repos/Gronod/argyllcms/releases/latest GET https://api.github.com/repos/Gronod/argyllcms/releases/tags/${ARGYLL_RELEASE_TAG} ``` User-Agent required (`ICCery-fetch-argyll`). Accept `application/vnd.github+json`. **Asset selection** | `--platform` | Asset name must end with | |---|---| | `linux-x86_64` | `_linux_x86_64_bin.tgz` | | `windows-x86_64` | `_win64_exe.zip` | | `macos-x86_64` | `_macOS_x86_64_bin.tgz` | | `macos-aarch64` | `_macOS_arm64_bin.tgz` | Download **only the current platform**. The Linux tarball is ~100 MB; do not pull all four. **Extract and stage** 1. Download to a temp dir. 2. Extract (`.zip` via `unzip` / PowerShell `Expand-Archive` / Node; `.tgz` via `tar`). 3. Find the archive root: the unique top-level `Argyll_V*` directory. Fail if missing or if `bin/` is missing inside it. 4. Replace dest contents: - `linux-x86_64` / `macos-*`: copy `bin/*` → `src-tauri/argyll/<platform>/` - `windows-x86_64`: copy `bin/*` → `src-tauri/argyll/windows-x86_64/` **and** copy the entire `usb/` tree → `src-tauri/argyll/usb/` 5. Copy `License.txt` from the archive root into the platform dest (AGPL). 6. Do **not** touch `src-tauri/argyll/reference_gamuts/` or `src-tauri/argyll/mocks/`. 7. Skip work if dest already contains `instlist` / `instlist.exe` unless `--force`. 8. **Fail hard** (non-zero exit) if: - API/asset/download/extract fails - `bin/` is empty - Windows: `usb/ArgyllCMS_install_USB.exe` is missing after staging - `instlist` / `instlist.exe` is missing after staging **Cache:** skip when the marker binary exists. CI always passes `--force`. **`package.json`** ```json "scripts": { "fetch-argyll": "node scripts/fetch-argyll.mjs", "tauri": "tauri" } ``` Do not auto-run fetch on every `tauri` invocation; local `tauri dev` should use a previously fetched tree. Document `npm run fetch-argyll` as a prerequisite. **`src-tauri/build.rs`** Do **not** download from `build.rs` (no network in some environments; breaks Cargo incremental). If `instlist` / `instlist.exe` is missing for this OS, `panic!` with: ```text ArgyllCMS sidecars not found. Run `npm run fetch-argyll` from the repo root before `tauri build` / `tauri dev`. ``` --- ### 2. Stop committing binaries **`.gitignore`** — add: ```gitignore src-tauri/argyll/linux-x86_64/ src-tauri/argyll/windows-x86_64/ src-tauri/argyll/macos-x86_64/ src-tauri/argyll/macos-aarch64/ src-tauri/argyll/usb/ ``` Keep `src-tauri/argyll/reference_gamuts/` tracked. **Remove from the index** (leave git history as-is): ```bash git rm -r --cached src-tauri/argyll/linux-x86_64 src-tauri/argyll/windows-x86_64 ``` **Mocks:** move `chartread.mock`, `colprof.mock`, `profcheck.mock` to `src-tauri/argyll/mocks/` or delete them. They must not live under a gitignored platform dir. --- ### 3. CI — fetch, then fail if sidecars are missing Update **all six** workflow files (GitHub + Gitea, three platforms). Replace “Check sidecar binaries” and “Prepare platform-specific resources” with a fetch + hard verify. The “delete the other OS’s binaries” step becomes unnecessary (they will not be present) and should be removed. Place fetch **after** `npm ci` (the script is invoked via `npm run fetch-argyll`). #### Linux (`.github/workflows/build-linux.yml` and `.gitea/workflows/build-linux.yml`) Remove: ```yaml - name: Prepare platform-specific resources run: | echo "Removing Windows ArgyllCMS binaries..." rm -rf src-tauri/argyll/windows-x86_64 ``` Add (after `npm ci`): ```yaml - name: Fetch ArgyllCMS binaries env: ARGYLL_RELEASE_TAG: ${{ vars.ARGYLL_RELEASE_TAG }} GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: npm run fetch-argyll -- --force --platform linux-x86_64 - name: Verify sidecar binaries run: | test -x src-tauri/argyll/linux-x86_64/instlist test -x src-tauri/argyll/linux-x86_64/targen test -x src-tauri/argyll/linux-x86_64/chartread test -x src-tauri/argyll/linux-x86_64/colprof ``` #### Windows (`.github/workflows/build-windows.yml` and `.gitea/workflows/build-windows.yml`) **This is the instlist fix.** Delete the current warning-only step that tests `argyll-instlist.exe`. Replace with: ```yaml - name: Fetch ArgyllCMS binaries shell: powershell env: ARGYLL_RELEASE_TAG: ${{ vars.ARGYLL_RELEASE_TAG }} GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: npm run fetch-argyll -- --force --platform windows-x86_64 - name: Verify sidecar binaries shell: powershell run: | $required = @( "src-tauri\argyll\windows-x86_64\instlist.exe", "src-tauri\argyll\windows-x86_64\targen.exe", "src-tauri\argyll\windows-x86_64\chartread.exe", "src-tauri\argyll\windows-x86_64\colprof.exe", "src-tauri\argyll\usb\ArgyllCMS_install_USB.exe", "src-tauri\argyll\usb\ArgyllCMS.inf" ) foreach ($p in $required) { if (!(Test-Path $p)) { throw "Missing required ArgyllCMS file: $p" } } ``` Also remove the “Prepare platform-specific resources” step that deletes `src-tauri\argyll\linux-x86_64`. #### macOS (`.github/workflows/build-macos.yml` and `.gitea/workflows/build-macos.yml`) The matrix already has `binary_dir: macos-x86_64` / `macos-aarch64`. Replace the warning-only “Check sidecar binaries” step: ```yaml - name: Fetch ArgyllCMS binaries env: ARGYLL_RELEASE_TAG: ${{ vars.ARGYLL_RELEASE_TAG }} GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: npm run fetch-argyll -- --force --platform ${{ matrix.platform.binary_dir }} - name: Verify sidecar binaries run: | test -x "src-tauri/argyll/${{ matrix.platform.binary_dir }}/instlist" test -x "src-tauri/argyll/${{ matrix.platform.binary_dir }}/targen" ``` `vars.ARGYLL_RELEASE_TAG` is optional. Empty means “latest”. Set it on the repo if a release must pin a known-good Argyll tag. Gitea `secrets.GITHUB_TOKEN` is the Gitea job token; GitHub API still works unauthenticated for this public repo. Passing it is harmless if the host is Gitea (GitHub will ignore a Gitea token). If Gitea rate-limits become an issue, add a `GH_API_TOKEN` secret for `api.github.com`. --- ### 4. Windows installer — optional USB drivers Two parts: **bundle the files** (automatic once fetch stages `argyll/usb/**`) and **offer to run the installer**. #### `src-tauri/tauri.conf.json` Keep `"resources": ["argyll/**/*"]` — that already picks up `argyll/usb/**`. Change the NSIS block: ```json "windows": { "wix": { "bannerPath": "icons/wix-banner.bmp", "dialogImagePath": "icons/wix-dialog.bmp" }, "nsis": { "installMode": "both", "installerIcon": "icons/icon.ico", "headerImage": "icons/nsis-header.bmp", "sidebarImage": "icons/nsis-sidebar.bmp", "installerHooks": "windows/hooks.nsh" } } ``` `installMode: "both"` is required. USB driver install needs admin; default Tauri NSIS is current-user and the driver installer will fail or UAC-loop. Keep current-user as a choice; only prompt for USB when the NSIS run is elevated. #### New file: `src-tauri/windows/hooks.nsh` Tauri v2 NSIS hooks are `NSIS_HOOK_PREINSTALL`, `NSIS_HOOK_POSTINSTALL`, `NSIS_HOOK_PREUNINSTALL`, `NSIS_HOOK_POSTUNINSTALL`. There is no custom MUI page hook without forking the NSIS template. A Yes/No at install time is the intended UX. ```nsis Var InstallArgyllUSB !macro NSIS_HOOK_PREINSTALL StrCpy $InstallArgyllUSB 0 ${If} ${IsUserAdmin} MessageBox MB_YESNO|MB_ICONQUESTION \ "Install ArgyllCMS USB instrument drivers?$\r$\n$\r$\nRequired for spectrophotometers (i1Pro, ColorMunki, SpyderPrint, etc.)." \ IDNO skip_usb_prompt StrCpy $InstallArgyllUSB 1 skip_usb_prompt: ${EndIf} !macroend !macro NSIS_HOOK_POSTINSTALL ${If} $InstallArgyllUSB == 1 ; Confirm this path with one NSIS build. Tauri v2 typically places ; bundle.resources next to the exe, so: ; $INSTDIR\argyll\usb\ArgyllCMS_install_USB.exe ; If the first build puts them under $INSTDIR\resources\..., update this line. IfFileExists "$INSTDIR\argyll\usb\ArgyllCMS_install_USB.exe" 0 usb_missing ExecWait '"$INSTDIR\argyll\usb\ArgyllCMS_install_USB.exe"' Goto usb_done usb_missing: MessageBox MB_ICONEXCLAMATION "ArgyllCMS USB driver installer was not found in the package." usb_done: ${EndIf} !macroend !macro NSIS_HOOK_PREUNINSTALL !macroend !macro NSIS_HOOK_POSTUNINSTALL ; Do not auto-run ArgyllCMS_uninstall_USB.exe. Driver removal is a ; separate admin action and can break other Argyll-based apps. !macroend ``` Rules: - Do **not** run the USB installer silently. It has its own GUI and needs the inf/sys/cat tree next to it. - Do **not** prompt when the installer is not elevated. - After the first NSIS build, confirm the on-disk path (`$INSTDIR\argyll\usb\...` vs `$INSTDIR\resources\argyll\usb\...`) and fix `ExecWait` if needed. - `${IsUserAdmin}` requires `LogicLib.nsh` / `UserInfo` — the stock Tauri NSIS template already includes LogicLib. If the hook fails to compile, add `!include "LogicLib.nsh"` at the top of `hooks.nsh` (only if the template does not already include it). #### MSI / WiX WiX has no NSIS-style hook. Out of scope for the first cut unless cheap: - Minimum: USB files are still inside the MSI via `argyll/**/*`. Add a Start Menu shortcut “Install USB instrument drivers” pointing at `argyll\usb\ArgyllCMS_install_USB.exe`. - Full parity: WiX fragment with an optional `Feature` + `CustomAction`. Not required for this ticket. NSIS (`.exe`) is the installer that must prompt at install time. --- ### 5. Docs **`README.md` — Building from Source** Add before `npm run tauri dev`: ```bash # Download ArgyllCMS sidecars for this OS (from github.com/Gronod/argyllcms/releases) npm run fetch-argyll ``` Note: - Windows NSIS setup offers an optional “Install ArgyllCMS USB instrument drivers” step (admin / per-machine). - Override the Argyll release with `ARGYLL_RELEASE_TAG=vX.Y.Z npm run fetch-argyll`. - Sidecars are not in git; `tauri build` / `tauri dev` will fail until fetch has been run once. **`ROADMAP.md`** One bullet under the current milestone / packaging: Argyll sidecars fetched from Gronod/argyllcms releases; Windows NSIS USB driver option. **`THIRDPARTY-LICENSES.md`** Point at the bundled `License.txt` that ships with the fetched archive (AGPLv3). --- ## File checklist | File | Action | |---|---| | `scripts/fetch-argyll.mjs` | **Create** | | `package.json` | Add `fetch-argyll` script | | `.gitignore` | Ignore platform binary dirs + `argyll/usb/` | | `src-tauri/argyll/linux-x86_64/` | `git rm -r --cached` | | `src-tauri/argyll/windows-x86_64/` | `git rm -r --cached` | | `src-tauri/argyll/mocks/` | Move or delete the three `.mock` files | | `src-tauri/build.rs` | Panic if `instlist` missing | | `src-tauri/tauri.conf.json` | `nsis.installMode: "both"`, `nsis.installerHooks` | | `src-tauri/windows/hooks.nsh` | **Create** | | `.github/workflows/build-windows.yml` | Fetch + **fail on missing `instlist.exe`** (not `argyll-instlist.exe`) | | `.github/workflows/build-linux.yml` | Fetch + fail on missing `instlist` | | `.github/workflows/build-macos.yml` | Fetch + fail on missing `instlist` | | `.gitea/workflows/build-windows.yml` | Same as GitHub Windows | | `.gitea/workflows/build-linux.yml` | Same as GitHub Linux | | `.gitea/workflows/build-macos.yml` | Same as GitHub macOS | | `README.md` | Fetch prerequisite + USB option | | `ROADMAP.md` | Short note | | `THIRDPARTY-LICENSES.md` | Bundled Argyll license pointer | No change to `resolve_binary` path layout unless a fetch dry-run shows a different `bin/` shape. --- ## Implementation order 1. Write `scripts/fetch-argyll.mjs`. Dry-run on Linux: confirm `bin/` lands in `src-tauri/argyll/linux-x86_64/` and `instlist` is executable. Dry-run the Windows zip on any OS with `--platform windows-x86_64`: confirm `instlist.exe` and `usb/ArgyllCMS_install_USB.exe`. 2. `.gitignore` + `git rm --cached` the vendored trees; relocate/drop `.mock` files. 3. `build.rs` missing-sidecar panic. 4. Wire fetch + hard verify into all six workflows. **Windows verify must use `instlist.exe`.** 5. `tauri.conf.json` `installMode: "both"` + `windows/hooks.nsh`. 6. One Windows NSIS build: confirm `$INSTDIR\...\ArgyllCMS_install_USB.exe` exists in the staged installer payload, Yes launches it, No skips it, current-user install does not prompt (or prompts only when admin). 7. README / ROADMAP / licenses. --- ## Acceptance criteria - [ ] `src-tauri/argyll/linux-x86_64/` and `src-tauri/argyll/windows-x86_64/` are not tracked by git. `reference_gamuts/` still is. - [ ] `npm run fetch-argyll` on Linux populates `linux-x86_64/` from `https://github.com/Gronod/argyllcms/releases/latest` (or `ARGYLL_RELEASE_TAG`). - [ ] `npm run fetch-argyll -- --platform windows-x86_64` populates `windows-x86_64/` **and** `usb/`, including `ArgyllCMS_install_USB.exe` and `ArgyllCMS.inf`. - [ ] Fetch of the wrong/missing asset exits non-zero. - [ ] Linux / Windows / macOS CI (GitHub **and** Gitea) fetch before `tauri build` and **fail** if `instlist` / `ins
gronod added the Kind/Feature label 2026-08-28 23:15:48 +01:00
gronod pinned this 2026-08-28 23:16:24 +01:00
Sign in to join this conversation.