fix: actually generate the UTF-8 locale makensis needs
`locale-gen <name>` is an Ubuntu extension; plain Debian's locale-gen takes no arguments and only reads /etc/locale.gen, so the previous fix generated nothing and makensis kept aborting with exit 84 / "FATAL: main argv conversion failed!" under the runner's C/POSIX locale. Write the entry into /etc/locale.gen, run locale-gen with no arguments, and assert `locale -a` lists it — a missing locale now fails the install step with a clear message instead of dying four minutes later inside electron-builder. build-release.ps1 sets LC_ALL/LANG itself before packaging a Windows target on a Linux host, picking a real UTF-8 locale out of `locale -a`. The electron-builder child then inherits it however the script was started, including a runner that drops step env. Also adds a non-fatal probe step that runs the cached makensis with -VERSION under en_US.UTF-8 and under C, so a failure that is *not* the locale is distinguishable from one that is without another blind fix. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -63,9 +63,22 @@ jobs:
|
||||
sudo dpkg --add-architecture i386
|
||||
sudo apt-get update
|
||||
sudo apt-get install -y jq wine locales
|
||||
# C.UTF-8 is glibc >=2.35 only (Debian 12+); en_US.UTF-8 works on any
|
||||
# Debian version and just needs generating once.
|
||||
sudo locale-gen en_US.UTF-8
|
||||
# makensis converts its argv through the locale charset and aborts with
|
||||
# "FATAL: main argv conversion failed!" under C/POSIX. C.UTF-8 is a glibc
|
||||
# built-in only from 2.35 (Debian 12+), so en_US.UTF-8 is generated instead.
|
||||
#
|
||||
# `locale-gen <name>` is an Ubuntu extension: plain Debian's locale-gen
|
||||
# takes no arguments and only reads /etc/locale.gen, so the entry goes in
|
||||
# there first. The anchored grep does not match the line the package ships
|
||||
# commented out.
|
||||
grep -q '^en_US.UTF-8 UTF-8' /etc/locale.gen \
|
||||
|| echo 'en_US.UTF-8 UTF-8' | sudo tee -a /etc/locale.gen
|
||||
sudo locale-gen
|
||||
locale -a
|
||||
locale -a | grep -qiE '^en_US\.utf-?8$' || {
|
||||
echo "en_US.UTF-8 was not generated; makensis will abort on argv conversion" >&2
|
||||
exit 1
|
||||
}
|
||||
|
||||
- name: Ensure PowerShell
|
||||
# Debian ships no snapd by default, so this pulls Microsoft's portable
|
||||
@@ -82,6 +95,25 @@ jobs:
|
||||
sudo ln -sf /opt/microsoft/powershell/7/pwsh /usr/bin/pwsh
|
||||
sudo chmod +x /opt/microsoft/powershell/7/pwsh
|
||||
|
||||
- name: makensis locale probe
|
||||
# Diagnostic only, never fails the job. If `-VERSION` prints a version under
|
||||
# en_US.UTF-8 and "FATAL: main argv conversion failed!" under C, the locale
|
||||
# really is the whole story. If it fails under both, it is not the locale and
|
||||
# the next thing to try is DEBUG=electron-builder on the build step to see the
|
||||
# argv makensis is actually handed. Prints nothing useful on the very first
|
||||
# run of a fresh runner, where the NSIS bundle has not been downloaded yet.
|
||||
continue-on-error: true
|
||||
run: |
|
||||
locale || true
|
||||
mk=$(find "$HOME/.cache/electron-builder" /var/lib/gitea-runner/.cache/electron-builder \
|
||||
-type f -name makensis -path '*/linux/*' 2>/dev/null | head -n1)
|
||||
echo "makensis: ${mk:-<not downloaded yet>}"
|
||||
[ -n "$mk" ] || exit 0
|
||||
echo "--- LC_ALL=en_US.UTF-8"
|
||||
LC_ALL=en_US.UTF-8 LANG=en_US.UTF-8 "$mk" -VERSION || echo "failed, exit $?"
|
||||
echo "--- LC_ALL=C"
|
||||
LC_ALL=C LANG=C "$mk" -VERSION || echo "failed, exit $?"
|
||||
|
||||
- name: Build Windows installers + Linux AppImage
|
||||
shell: pwsh
|
||||
env:
|
||||
|
||||
@@ -169,6 +169,54 @@ function Invoke-Checked {
|
||||
}
|
||||
}
|
||||
|
||||
function Set-Utf8Locale {
|
||||
<#
|
||||
electron-builder's native Linux makensis converts its own argv through the
|
||||
locale charset before it parses anything, and cannot do it under a non-UTF-8
|
||||
locale:
|
||||
|
||||
⨯ .../nsis-3.0.4.1/linux/makensis process failed ERR_ELECTRON_BUILDER_CANNOT_EXECUTE
|
||||
Exit code: 84
|
||||
Output: FATAL: main argv conversion failed!
|
||||
|
||||
A minimal Debian box — a CI runner in particular — defaults to C/POSIX,
|
||||
which is exactly that case. Setting it here rather than only in the CI
|
||||
workflow's env: block means the electron-builder child inherits it however
|
||||
this script was started: a runner that drops step env, a bare
|
||||
`pwsh ./scripts/build-release.ps1` over ssh, cron.
|
||||
|
||||
Which locales exist is a property of the host, so `locale -a` is consulted
|
||||
rather than guessed at: C.UTF-8 is a glibc built-in only from 2.35
|
||||
(Debian 12+), and en_US.UTF-8 exists only once someone has run locale-gen.
|
||||
#>
|
||||
$current = if ($env:LC_ALL) { $env:LC_ALL } else { $env:LANG }
|
||||
if ($current -match '(?i)\.utf-?8$') { return }
|
||||
|
||||
$available = @()
|
||||
try { $available = @(& locale -a 2>$null) } catch { }
|
||||
|
||||
# Debian spells them "C.utf8" / "en_US.utf8" in `locale -a` but wants
|
||||
# "en_US.UTF-8 UTF-8" in /etc/locale.gen; both spellings are accepted by
|
||||
# setlocale, so match either and fall back to any UTF-8 locale at all.
|
||||
$pick = @("C.UTF-8", "C.utf8", "en_US.UTF-8", "en_US.utf8") |
|
||||
Where-Object { $available -contains $_ } | Select-Object -First 1
|
||||
if (-not $pick) {
|
||||
$pick = $available | Where-Object { $_ -match '(?i)\.utf-?8$' } | Select-Object -First 1
|
||||
}
|
||||
if (-not $pick) {
|
||||
throw ("no UTF-8 locale on this host, and makensis aborts with 'FATAL: main argv " +
|
||||
"conversion failed!' without one. Generate one:`n" +
|
||||
" sudo apt-get install -y locales`n" +
|
||||
" echo 'en_US.UTF-8 UTF-8' | sudo tee -a /etc/locale.gen`n" +
|
||||
" sudo locale-gen`n" +
|
||||
"then re-run. 'locale -a' listed: $($available -join ', ')")
|
||||
}
|
||||
|
||||
Write-Host " locale: LC_ALL=$pick (was '$current'; makensis needs UTF-8)" -ForegroundColor DarkGray
|
||||
$env:LC_ALL = $pick
|
||||
$env:LANG = $pick
|
||||
}
|
||||
|
||||
function Get-ArtifactName {
|
||||
<#
|
||||
electron-builder rejects an artifactName that has no ${ext} macro, and
|
||||
@@ -562,6 +610,14 @@ try {
|
||||
"mkdir -p $(ConvertTo-BashArg $wslStage) && rm -f $(ConvertTo-BashArg $wslStage)/$prefix-*")
|
||||
}
|
||||
|
||||
# Both Windows targets go through makensis (portable is an NSIS build too), and
|
||||
# on a Linux host that is a native binary this process's locale reaches. The WSL
|
||||
# path is not covered: wsl.exe does not carry $env:LC_ALL into the distro, and a
|
||||
# distro someone installed interactively has a UTF-8 locale already.
|
||||
if (-not $onWindows -and @($resolvedTargets | Where-Object { $_ -like "win*" }).Count) {
|
||||
Set-Utf8Locale
|
||||
}
|
||||
|
||||
foreach ($target in $resolvedTargets) {
|
||||
Write-Host "Packaging $target..." -ForegroundColor Cyan
|
||||
|
||||
|
||||
Reference in New Issue
Block a user