bitcoin/test/lint/lint-shell-locale.py
MarcoFalke fae612424b
contrib: Remove confusing and redundant encoding from IO
The encoding arg is confusing, because it is not applied consistently
for all IO.

Also, it is useless, as the majority of files are ASCII encoded, which
are fine to encode and decode with any mode.

Moreover, UTF-8 is already required for most scripts to work properly,
so setting the encoding twice is redundant.

So remove the encoding from most IO. It would be fine to remove from all
IO, however I kept it for two files:

* contrib/asmap/asmap-tool.py: This specifically looks for utf-8
  encoding errors, so it makes sense to sepecify the utf-8 encoding
  explicitly.
* test/functional/test_framework/test_node.py: Reading the debug log in
  text mode specifically counts the utf-8 characters (not bytes), so it
  makes sense to specify the utf-8 encoding explicitly.
2025-11-26 11:31:16 +01:00

62 lines
1.8 KiB
Python
Executable File

#!/usr/bin/env python3
#
# Copyright (c) 2018-present The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""
Make sure all shell scripts explicitly opt out of locale dependence using
"export LC_ALL=C" or "export LC_ALL=C.UTF-8", which also enables UTF-8 mode in
Python. See: https://docs.python.org/3/library/os.html#python-utf-8-mode
"""
import subprocess
import sys
import re
OPT_OUT_LINES = [
'export LC_ALL=C',
'export LC_ALL=C.UTF-8',
]
def get_shell_files_list():
command = [
'git',
'ls-files',
'--',
'*.sh',
]
try:
return subprocess.check_output(command, stderr = subprocess.STDOUT).decode('utf-8').splitlines()
except subprocess.CalledProcessError as e:
if e.returncode > 1: # return code is 1 when match is empty
print(e.output.decode('utf-8'), end='')
sys.exit(1)
return []
def main():
exit_code = 0
shell_files = get_shell_files_list()
for file_path in shell_files:
if re.search('src/(secp256k1|minisketch)/', file_path):
continue
with open(file_path, 'r') as file_obj:
contents = file_obj.read()
non_comment_pattern = re.compile(r'^\s*((?!#).+)$', re.MULTILINE)
non_comment_lines = re.findall(non_comment_pattern, contents)
if not non_comment_lines:
continue
first_non_comment_line = non_comment_lines[0]
if first_non_comment_line not in OPT_OUT_LINES:
print(f'Missing "export LC_ALL=C" (to avoid locale dependence) as first non-comment non-empty line in {file_path}')
exit_code = 1
return sys.exit(exit_code)
if __name__ == '__main__':
main()