Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions gitlint-core/gitlint/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ def log_system_info():
LOG.debug("Git version: %s", git_version())
LOG.debug("Gitlint version: %s", gitlint.__version__)
LOG.debug("GITLINT_USE_SH_LIB: %s", os.environ.get("GITLINT_USE_SH_LIB", "[NOT SET]"))
LOG.debug("DEFAULT_ENCODING: %s", gitlint.utils.DEFAULT_ENCODING)
LOG.debug("DEFAULT_ENCODING: %s", gitlint.utils.TERMINAL_ENCODING)


def build_config(
Expand Down Expand Up @@ -264,7 +264,7 @@ def __init__(self, config, config_builder, commit_hash, refspec, msg_filename, g
@click.option("--ignore", envvar="GITLINT_IGNORE", default="", help="Ignore rules (comma-separated by id or name).")
@click.option("--contrib", envvar="GITLINT_CONTRIB", default="",
help="Contrib rules to enable (comma-separated by id or name).")
@click.option("--msg-filename", type=click.File(encoding=gitlint.utils.DEFAULT_ENCODING),
@click.option("--msg-filename", type=click.File(encoding=gitlint.utils.FILE_ENCODING),
help="Path to a file containing a commit-msg.")
@click.option("--ignore-stdin", envvar="GITLINT_IGNORE_STDIN", is_flag=True,
help="Ignore any stdin data. Useful for running in CI server.")
Expand Down
4 changes: 2 additions & 2 deletions gitlint-core/gitlint/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
)
from gitlint.contrib import rules as contrib_rules
from gitlint.exception import GitlintError
from gitlint.utils import DEFAULT_ENCODING
from gitlint.utils import FILE_ENCODING


def handle_option_error(func):
Expand Down Expand Up @@ -468,7 +468,7 @@ def set_from_config_file(self, filename):
try:
parser = ConfigParser()

with open(filename, encoding=DEFAULT_ENCODING) as config_file:
with open(filename, encoding=FILE_ENCODING) as config_file:
parser.read_file(config_file, filename)

for section_name in parser.sections():
Expand Down
4 changes: 2 additions & 2 deletions gitlint-core/gitlint/hooks.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

from gitlint.exception import GitlintError
from gitlint.git import git_hooks_dir
from gitlint.utils import DEFAULT_ENCODING
from gitlint.utils import FILE_ENCODING

COMMIT_MSG_HOOK_SRC_PATH = os.path.join(os.path.dirname(os.path.realpath(__file__)), "files", "commit-msg")
COMMIT_MSG_HOOK_DST_PATH = "commit-msg"
Expand Down Expand Up @@ -52,7 +52,7 @@ def uninstall_commit_msg_hook(lint_config):
if not os.path.exists(dest_path):
raise GitHookInstallerError(f"There is no commit-msg hook present in {dest_path}.")

with open(dest_path, encoding=DEFAULT_ENCODING) as fp:
with open(dest_path, encoding=FILE_ENCODING) as fp:
lines = fp.readlines()
if len(lines) < 2 or lines[1] != GITLINT_HOOK_IDENTIFIER:
msg = (
Expand Down
4 changes: 2 additions & 2 deletions gitlint-core/gitlint/shell.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

import subprocess

from gitlint.utils import DEFAULT_ENCODING, USE_SH_LIB
from gitlint.utils import TERMINAL_ENCODING, USE_SH_LIB


def shell(cmd):
Expand Down Expand Up @@ -64,7 +64,7 @@ def _exec(*args, **kwargs):
raise CommandNotFound from e

exit_code = p.returncode
stdout = result[0].decode(DEFAULT_ENCODING)
stdout = result[0].decode(TERMINAL_ENCODING)
stderr = result[1] # 'sh' does not decode the stderr bytes to unicode
full_cmd = "" if args is None else " ".join(args)

Expand Down
6 changes: 3 additions & 3 deletions gitlint-core/gitlint/tests/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
from gitlint.deprecation import LOG as DEPRECATION_LOG
from gitlint.deprecation import Deprecation
from gitlint.git import GitChangedFileStats, GitContext
from gitlint.utils import DEFAULT_ENCODING, LOG_FORMAT
from gitlint.utils import FILE_ENCODING, LOG_FORMAT

EXPECTED_REGEX_STYLE_SEARCH_DEPRECATION_WARNING = (
"WARNING: gitlint.deprecated.regex_style_search {0} - {1}: gitlint will be switching from using "
Expand Down Expand Up @@ -95,7 +95,7 @@ def get_sample_path(filename=""):
def get_sample(filename=""):
"""Read and return the contents of a file in gitlint/tests/samples"""
sample_path = BaseTestCase.get_sample_path(filename)
return Path(sample_path).read_text(encoding=DEFAULT_ENCODING)
return Path(sample_path).read_text(encoding=FILE_ENCODING)

@staticmethod
def patch_input(side_effect):
Expand All @@ -109,7 +109,7 @@ def get_expected(filename="", variable_dict=None):
"""Utility method to read an expected file from gitlint/tests/expected and return it as a string.
Optionally replace template variables specified by variable_dict."""
expected_path = os.path.join(BaseTestCase.EXPECTED_DIR, filename)
expected = Path(expected_path).read_text(encoding=DEFAULT_ENCODING)
expected = Path(expected_path).read_text(encoding=FILE_ENCODING)

if variable_dict:
expected = expected.format(**variable_dict)
Expand Down
8 changes: 4 additions & 4 deletions gitlint-core/gitlint/tests/cli/test_cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
from gitlint import __version__, cli
from gitlint.shell import CommandNotFound
from gitlint.tests.base import BaseTestCase
from gitlint.utils import DEFAULT_ENCODING
from gitlint.utils import FILE_ENCODING, TERMINAL_ENCODING


class CLITests(BaseTestCase):
Expand Down Expand Up @@ -39,7 +39,7 @@ def get_system_info_dict():
"gitlint_version": __version__,
"GITLINT_USE_SH_LIB": BaseTestCase.GITLINT_USE_SH_LIB,
"target": os.path.realpath(os.getcwd()),
"DEFAULT_ENCODING": DEFAULT_ENCODING,
"DEFAULT_ENCODING": TERMINAL_ENCODING,
}

def test_version(self):
Expand Down Expand Up @@ -315,7 +315,7 @@ def test_lint_staged_msg_filename(self, sh, _):

with self.tempdir() as tmpdir:
msg_filename = os.path.join(tmpdir, "msg")
with open(msg_filename, "w", encoding=DEFAULT_ENCODING) as f:
with open(msg_filename, "w", encoding=FILE_ENCODING) as f:
f.write("WIP: msg-filename tïtle\n")

with patch("gitlint.display.stderr", new=StringIO()) as stderr:
Expand Down Expand Up @@ -370,7 +370,7 @@ def test_msg_filename(self, _):

with self.tempdir() as tmpdir:
msg_filename = os.path.join(tmpdir, "msg")
with open(msg_filename, "w", encoding=DEFAULT_ENCODING) as f:
with open(msg_filename, "w", encoding=FILE_ENCODING) as f:
f.write("Commït title\n")

with patch("gitlint.display.stderr", new=StringIO()) as stderr:
Expand Down
10 changes: 5 additions & 5 deletions gitlint-core/gitlint/tests/cli/test_cli_hooks.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
from gitlint import cli, config, hooks
from gitlint.shell import ErrorReturnCode
from gitlint.tests.base import BaseTestCase
from gitlint.utils import DEFAULT_ENCODING
from gitlint.utils import FILE_ENCODING


class CLIHookTests(BaseTestCase):
Expand Down Expand Up @@ -102,7 +102,7 @@ def test_run_hook_no_tty(self):

with self.tempdir() as tmpdir:
msg_filename = os.path.join(tmpdir, "hür")
with open(msg_filename, "w", encoding=DEFAULT_ENCODING) as f:
with open(msg_filename, "w", encoding=FILE_ENCODING) as f:
f.write("WIP: tïtle\n")

with patch("gitlint.display.stderr", new=StringIO()) as stderr:
Expand Down Expand Up @@ -130,7 +130,7 @@ def test_run_hook_edit(self, shell):

with self.patch_input(["e", "e", "n"]), self.tempdir() as tmpdir:
msg_filename = os.path.realpath(os.path.join(tmpdir, "hür"))
with open(msg_filename, "w", encoding=DEFAULT_ENCODING) as f:
with open(msg_filename, "w", encoding=FILE_ENCODING) as f:
f.write(commit_messages[i] + "\n")

with patch("gitlint.display.stderr", new=StringIO()) as stderr:
Expand Down Expand Up @@ -158,7 +158,7 @@ def test_run_hook_no(self):

with self.patch_input(["n"]), self.tempdir() as tmpdir:
msg_filename = os.path.join(tmpdir, "hür")
with open(msg_filename, "w", encoding=DEFAULT_ENCODING) as f:
with open(msg_filename, "w", encoding=FILE_ENCODING) as f:
f.write("WIP: höok no\n")

with patch("gitlint.display.stderr", new=StringIO()) as stderr:
Expand All @@ -175,7 +175,7 @@ def test_run_hook_yes(self):
"""Test for run-hook subcommand, answering 'y(es)' after commit-hook"""
with self.patch_input(["y"]), self.tempdir() as tmpdir:
msg_filename = os.path.join(tmpdir, "hür")
with open(msg_filename, "w", encoding=DEFAULT_ENCODING) as f:
with open(msg_filename, "w", encoding=FILE_ENCODING) as f:
f.write("WIP: höok yes\n")

with patch("gitlint.display.stderr", new=StringIO()) as stderr:
Expand Down
4 changes: 2 additions & 2 deletions gitlint-core/gitlint/tests/test_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ def test_use_sh_library(self, patched_env):
self.assertEqual(utils.use_sh_library(), False)

@patch("gitlint.utils.locale")
def test_default_encoding_non_windows(self, mocked_locale):
def test_terminal_encoding_non_windows(self, mocked_locale):
utils.PLATFORM_IS_WINDOWS = False
mocked_locale.getpreferredencoding.return_value = "foöbar"
self.assertEqual(utils.getpreferredencoding(), "foöbar")
Expand All @@ -37,7 +37,7 @@ def test_default_encoding_non_windows(self, mocked_locale):
self.assertEqual(utils.getpreferredencoding(), "UTF-8")

@patch("os.environ")
def test_default_encoding_windows(self, patched_env):
def test_terminal_encoding_windows(self, patched_env):
utils.PLATFORM_IS_WINDOWS = True
# Mock out os.environ
mock_env = {}
Expand Down
27 changes: 19 additions & 8 deletions gitlint-core/gitlint/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,39 +38,50 @@ def use_sh_library():
USE_SH_LIB = use_sh_library()

########################################################################################################################
# DEFAULT_ENCODING
# TERMINAL_ENCODING
# Encoding used for terminal encoding/decoding.


def getpreferredencoding():
"""Modified version of local.getpreferredencoding() that takes into account LC_ALL, LC_CTYPE, LANG env vars
on windows and falls back to UTF-8."""
fallback_encoding = "UTF-8"
default_encoding = locale.getpreferredencoding() or fallback_encoding
preferred_encoding = locale.getpreferredencoding() or fallback_encoding

# On Windows, we mimic git/linux by trying to read the LC_ALL, LC_CTYPE, LANG env vars manually
# (on Linux/MacOS the `getpreferredencoding()` call will take care of this).
# We fallback to UTF-8
if PLATFORM_IS_WINDOWS:
default_encoding = fallback_encoding
preferred_encoding = fallback_encoding
for env_var in ["LC_ALL", "LC_CTYPE", "LANG"]:
encoding = os.environ.get(env_var, False)
if encoding:
# Support dotted (C.UTF-8) and non-dotted (C or UTF-8) charsets:
# If encoding contains a dot: split and use second part, otherwise use everything
dot_index = encoding.find(".")
default_encoding = encoding[dot_index + 1 :] if dot_index != -1 else encoding
preferred_encoding = encoding[dot_index + 1 :] if dot_index != -1 else encoding
break

# We've determined what encoding the user *wants*, let's now check if it's actually a valid encoding on the
# system. If not, fallback to UTF-8.
# This scenario is fairly common on Windows where git sets LC_CTYPE=C when invoking the commit-msg hook, which
# is not a valid encoding in Python on Windows.
try:
codecs.lookup(default_encoding)
codecs.lookup(preferred_encoding)
except LookupError:
default_encoding = fallback_encoding
preferred_encoding = fallback_encoding

return default_encoding
return preferred_encoding


DEFAULT_ENCODING = getpreferredencoding()
TERMINAL_ENCODING = getpreferredencoding()

########################################################################################################################
# FILE_ENCODING
# Gitlint assumes UTF-8 encoding for all file operations:
# - reading/writing its own hook and config files
# - reading/writing git commit messages
# Git does have i18n.commitEncoding and i18n.logOutputEncoding options which we might want to take into account,
# but that's not supported today.

FILE_ENCODING = "UTF-8"
8 changes: 4 additions & 4 deletions qa/test_gitlint.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

from qa.base import BaseTestCase
from qa.shell import echo, git, gitlint
from qa.utils import DEFAULT_ENCODING
from qa.utils import FILE_ENCODING


class IntegrationTests(BaseTestCase):
Expand Down Expand Up @@ -58,7 +58,7 @@ def test_fixup_commit(self):
self.assertEqualStdout(output, expected)

# Make a small modification to the commit and commit it using fixup commit
with open(os.path.join(self.tmp_git_repo, test_filename), "a", encoding=DEFAULT_ENCODING) as fh:
with open(os.path.join(self.tmp_git_repo, test_filename), "a", encoding=FILE_ENCODING) as fh:
fh.write("Appending söme stuff\n")

git("add", test_filename, _cwd=self.tmp_git_repo)
Expand Down Expand Up @@ -87,7 +87,7 @@ def test_fixup_amend_commit(self):
self.assertEqualStdout(output, expected)

# Make a small modification to the commit and commit it using fixup=amend commit
with open(os.path.join(self.tmp_git_repo, test_filename), "a", encoding=DEFAULT_ENCODING) as fh:
with open(os.path.join(self.tmp_git_repo, test_filename), "a", encoding=FILE_ENCODING) as fh:
fh.write("Appending söme stuff\n")

git("add", test_filename, _cwd=self.tmp_git_repo)
Expand Down Expand Up @@ -133,7 +133,7 @@ def test_squash_commit(self):
self.assertEqualStdout(output, expected)

# Make a small modification to the commit and commit it using squash commit
with open(os.path.join(self.tmp_git_repo, test_filename), "a", encoding=DEFAULT_ENCODING) as fh:
with open(os.path.join(self.tmp_git_repo, test_filename), "a", encoding=FILE_ENCODING) as fh:
# Wanted to write a unicode string, but that's obnoxious if you want to do it across Python 2 and 3.
# https://stackoverflow.com/questions/22392377/
# error-writing-a-file-with-file-write-in-python-unicodeencodeerror
Expand Down