Preserve locale during brew startup

- Validate the locale charmap instead of trusting its name.
- Reuse filtered Linux locale settings to avoid `locale -a`.
This commit is contained in:
Mike McQuaid
2026-07-28 12:03:52 +01:00
parent e2f1384a87
commit 059785dc91
3 changed files with 71 additions and 10 deletions
+53
View File
@@ -39,6 +39,59 @@ RSpec.describe "Bash" do
end
end
describe "setup-locale" do
it "uses the macOS locale charmap rather than the locale name", :needs_macos do
setup_locale = [
"/bin/bash", "-c", <<~BASH, "bash", (HOMEBREW_LIBRARY_PATH/"utils/os.sh").to_s
source "$1"
locale() {
[[ "${LC_CTYPE:-${LANG:-}}" == "UTF-8" ]] && printf "UTF-8" || printf "US-ASCII"
}
setup-locale
printf "%s" "${LC_ALL-unset}"
BASH
]
invalid_stdout, invalid_stderr, invalid_status = Open3.capture3(
{ "LANG" => "C.utf8", "LC_CTYPE" => nil, "LC_ALL" => nil }, *setup_locale
)
valid_stdout, valid_stderr, valid_status = Open3.capture3(
{ "LANG" => nil, "LC_CTYPE" => "UTF-8", "LC_ALL" => nil }, *setup_locale
)
expect([invalid_stdout, invalid_stderr, invalid_status.success?,
valid_stdout, valid_stderr, valid_status.success?])
.to eq(["en_US.UTF-8", "", true, "unset", "", true])
end
it "restores filtered Linux locale variables and removes their copies" do
stdout, stderr, status = Open3.capture3(
{ "LANG" => nil, "LC_CTYPE" => nil, "LC_ALL" => nil },
"/bin/bash", "-c", <<~'BASH', "bash", (HOMEBREW_LIBRARY_PATH/"utils/os.sh").to_s
source "$1"
HOMEBREW_MACOS=
HOMEBREW_LANG=C
HOMEBREW_LC_CTYPE=C
HOMEBREW_LC_ALL=C.UTF-8
locale() {
if [[ "$1" == "charmap" ]]
then
[[ "${LC_ALL:-}" == "C.UTF-8" ]] && printf "UTF-8" || printf "US-ASCII"
else
printf "locale -a called\n" >&2
printf "C.UTF-8\n"
fi
}
setup-locale
printf "%s\n" "${LANG-unset}" "${LC_CTYPE-unset}" "${LC_ALL-unset}" \
"${HOMEBREW_LANG-unset}" "${HOMEBREW_LC_CTYPE-unset}" "${HOMEBREW_LC_ALL-unset}"
BASH
)
expect([stdout, stderr, status.success?])
.to eq(["C\nC\nC.UTF-8\nunset\nunset\nunset\n", "", true])
end
end
describe "every `.sh` file" do
it "has valid Bash syntax" do
Pathname.glob("#{HOMEBREW_LIBRARY_PATH}/**/*.sh").each do |path|
+16 -10
View File
@@ -99,24 +99,30 @@ then
fi
# Force UTF-8 to avoid encoding issues for users with broken locale settings.
# The locale is checked by name to avoid forking `locale charmap`. When
# bin/brew has filtered the environment no locale variables survive so a UTF-8
# one must be set.
# Validate the active locale's charmap rather than trusting its name before
# selecting a usable fallback.
setup-locale() {
local utf8_locale_regex='\.([Uu][Tt][Ff]-?8)(@|$)'
local locales c_utf_regex en_us_regex utf_regex
if [[ "${LC_ALL:-${LC_CTYPE:-${LANG:-}}}" =~ ${utf8_locale_regex} ]]
if [[ -z "${HOMEBREW_MACOS}" ]]
then
# The locale is already UTF-8.
:
elif [[ -n "${HOMEBREW_MACOS}" ]]
[[ -z "${HOMEBREW_LANG:-}" ]] || export LANG="${HOMEBREW_LANG}"
[[ -z "${HOMEBREW_LC_CTYPE:-}" ]] || export LC_CTYPE="${HOMEBREW_LC_CTYPE}"
[[ -z "${HOMEBREW_LC_ALL:-}" ]] || export LC_ALL="${HOMEBREW_LC_ALL}"
fi
unset HOMEBREW_LANG HOMEBREW_LC_CTYPE HOMEBREW_LC_ALL
if [[ -n "${HOMEBREW_MACOS}" ]]
then
export LC_ALL="en_US.UTF-8"
if [[ -z "${LC_ALL:-${LC_CTYPE:-${LANG:-}}}" ]] || [[ "$(locale charmap)" != "UTF-8" ]]
then
export LC_ALL="en_US.UTF-8"
fi
else
if ! command -v locale >/dev/null
then
export LC_ALL=C
else
elif [[ "$(locale charmap)" != "UTF-8" ]]
then
locales="$(locale -a)"
c_utf_regex='\bC\.(utf8|UTF-8)\b'
en_us_regex='\ben_US\.(utf8|UTF-8)\b'
+2
View File
@@ -235,6 +235,8 @@ USED_BY_HOMEBREW_VARS=(
GOBIN
GOPATH
LANG
LC_ALL
LC_CTYPE
NODENV_ROOT
PATH
PYENV_ROOT