1
0
Fork 0

Merging upstream version 2.18.1.

Signed-off-by: Daniel Baumann <daniel@debian.org>
This commit is contained in:
Daniel Baumann 2025-02-09 21:33:11 +01:00
parent 131d7bde70
commit 3396d2e509
Signed by: daniel
GPG key ID: FBB4F0E80A80222F
116 changed files with 718 additions and 410 deletions

View file

@ -1,11 +1,9 @@
from __future__ import annotations
import logging
import os.path
import sys
from typing import Dict
from typing import List
from typing import MutableMapping
from typing import Optional
from typing import Set
from pre_commit.errors import FatalError
from pre_commit.util import CalledProcessError
@ -18,7 +16,7 @@ logger = logging.getLogger(__name__)
NO_FS_MONITOR = ('-c', 'core.useBuiltinFSMonitor=false')
def zsplit(s: str) -> List[str]:
def zsplit(s: str) -> list[str]:
s = s.strip('\0')
if s:
return s.split('\0')
@ -27,8 +25,8 @@ def zsplit(s: str) -> List[str]:
def no_git_env(
_env: Optional[MutableMapping[str, str]] = None,
) -> Dict[str, str]:
_env: MutableMapping[str, str] | None = None,
) -> dict[str, str]:
# Too many bugs dealing with environment variables and GIT:
# https://github.com/pre-commit/pre-commit/issues/300
# In git 2.6.3 (maybe others), git exports GIT_WORK_TREE while running
@ -45,6 +43,7 @@ def no_git_env(
k in {
'GIT_EXEC_PATH', 'GIT_SSH', 'GIT_SSH_COMMAND', 'GIT_SSL_CAINFO',
'GIT_SSL_NO_VERIFY', 'GIT_CONFIG_COUNT',
'GIT_HTTP_PROXY_AUTHMETHOD',
}
}
@ -58,13 +57,15 @@ def get_root() -> str:
root = os.path.abspath(
cmd_output('git', 'rev-parse', '--show-cdup')[1].strip(),
)
git_dir = os.path.abspath(get_git_dir())
inside_git_dir = cmd_output(
'git', 'rev-parse', '--is-inside-git-dir',
)[1].strip()
except CalledProcessError:
raise FatalError(
'git failed. Is it installed, and are you in a Git repository '
'directory?',
)
if os.path.samefile(root, git_dir):
if inside_git_dir != 'false':
raise FatalError(
'git toplevel unexpectedly empty! make sure you are not '
'inside the `.git` directory of your repository.',
@ -73,15 +74,25 @@ def get_root() -> str:
def get_git_dir(git_root: str = '.') -> str:
opts = ('--git-common-dir', '--git-dir')
_, out, _ = cmd_output('git', 'rev-parse', *opts, cwd=git_root)
for line, opt in zip(out.splitlines(), opts):
if line != opt: # pragma: no branch (git < 2.5)
return os.path.normpath(os.path.join(git_root, line))
opt = '--git-dir'
_, out, _ = cmd_output('git', 'rev-parse', opt, cwd=git_root)
git_dir = out.strip()
if git_dir != opt:
return os.path.normpath(os.path.join(git_root, git_dir))
else:
raise AssertionError('unreachable: no git dir')
def get_git_common_dir(git_root: str = '.') -> str:
opt = '--git-common-dir'
_, out, _ = cmd_output('git', 'rev-parse', opt, cwd=git_root)
git_common_dir = out.strip()
if git_common_dir != opt:
return os.path.normpath(os.path.join(git_root, git_common_dir))
else: # pragma: no cover (git < 2.5)
return get_git_dir(git_root)
def get_remote_url(git_root: str) -> str:
_, out, _ = cmd_output('git', 'config', 'remote.origin.url', cwd=git_root)
return out.strip()
@ -95,7 +106,7 @@ def is_in_merge_conflict() -> bool:
)
def parse_merge_msg_for_conflicts(merge_msg: bytes) -> List[str]:
def parse_merge_msg_for_conflicts(merge_msg: bytes) -> list[str]:
# Conflicted files start with tabs
return [
line.lstrip(b'#').strip().decode()
@ -105,7 +116,7 @@ def parse_merge_msg_for_conflicts(merge_msg: bytes) -> List[str]:
]
def get_conflicted_files() -> Set[str]:
def get_conflicted_files() -> set[str]:
logger.info('Checking merge-conflict files only.')
# Need to get the conflicted files from the MERGE_MSG because they could
# have resolved the conflict by choosing one side or the other
@ -126,7 +137,7 @@ def get_conflicted_files() -> Set[str]:
return set(merge_conflict_filenames) | set(merge_diff_filenames)
def get_staged_files(cwd: Optional[str] = None) -> List[str]:
def get_staged_files(cwd: str | None = None) -> list[str]:
return zsplit(
cmd_output(
'git', 'diff', '--staged', '--name-only', '--no-ext-diff', '-z',
@ -137,7 +148,7 @@ def get_staged_files(cwd: Optional[str] = None) -> List[str]:
)
def intent_to_add_files() -> List[str]:
def intent_to_add_files() -> list[str]:
_, stdout, _ = cmd_output(
'git', 'status', '--ignore-submodules', '--porcelain', '-z',
)
@ -153,11 +164,11 @@ def intent_to_add_files() -> List[str]:
return intent_to_add
def get_all_files() -> List[str]:
def get_all_files() -> list[str]:
return zsplit(cmd_output('git', 'ls-files', '-z')[1])
def get_changed_files(old: str, new: str) -> List[str]:
def get_changed_files(old: str, new: str) -> list[str]:
diff_cmd = ('git', 'diff', '--name-only', '--no-ext-diff', '-z')
try:
_, out, _ = cmd_output(*diff_cmd, f'{old}...{new}')
@ -230,3 +241,18 @@ def check_for_cygwin_mismatch() -> None:
f' - python {exe_type[is_cygwin_python]}\n'
f' - git {exe_type[is_cygwin_git]}\n',
)
def get_best_candidate_tag(rev: str, git_repo: str) -> str:
"""Get the best tag candidate.
Multiple tags can exist on a SHA. Sometimes a moving tag is attached
to a version tag. Try to pick the tag that looks like a version.
"""
tags = cmd_output(
'git', *NO_FS_MONITOR, 'tag', '--points-at', rev, cwd=git_repo,
)[1].splitlines()
for tag in tags:
if '.' in tag:
return tag
return rev