mirror of
https://github.com/pre-commit/pre-commit.git
synced 2026-04-15 18:11:48 +04:00
Improve path canonicalization
The git toplevel is a path with all symlinks leading to the repository root resolved. When transforming the supplied files to paths relative to the repository's root we _also_ need to resolve all symlinks up to the repository's root in order to correctly handle different symlinked paths that eventually lead to the same repository. Such paths are currently accepted by git, but are not matched correctly in pre-commit, as they incorrectly show as out-of-tree. To relativize paths correctly we iteratively try to replace the trailing components of the absolute path until the repository root is matched. The root prefix is then substituted for the real path, yelding a path with the subtree path untouched. This allows to correctly supply a symlink within the working tree to git itself. For paths which are not directly given as an argument to git, using os.path.realpath() instead is sufficient. This allows pre-commit to see the subtree path in the same way as currently accepted by git.
This commit is contained in:
parent
9b18686168
commit
037bc078dc
1 changed files with 18 additions and 3 deletions
|
|
@ -156,21 +156,36 @@ def _add_run_options(parser: argparse.ArgumentParser) -> None:
|
|||
)
|
||||
|
||||
|
||||
def _canon_subpath(path: str, toplevel: str) -> str:
|
||||
tail = ''
|
||||
while len(path):
|
||||
if os.path.samefile(path, toplevel):
|
||||
return os.path.join(toplevel, tail)
|
||||
path, base = os.path.split(path)
|
||||
tail = os.path.join(base, tail)
|
||||
return tail
|
||||
|
||||
|
||||
def _canon_relpath(path: str, toplevel: str) -> str:
|
||||
return os.path.relpath(_canon_subpath(path, toplevel))
|
||||
|
||||
|
||||
def _adjust_args_and_chdir(args: argparse.Namespace) -> None:
|
||||
# `--config` was specified relative to the non-root working directory
|
||||
if os.path.exists(args.config):
|
||||
args.config = os.path.abspath(args.config)
|
||||
args.config = os.path.realpath(args.config)
|
||||
if args.command in {'run', 'try-repo'}:
|
||||
args.files = [os.path.abspath(filename) for filename in args.files]
|
||||
if args.command == 'try-repo' and os.path.exists(args.repo):
|
||||
args.repo = os.path.abspath(args.repo)
|
||||
args.repo = os.path.realpath(args.repo)
|
||||
|
||||
toplevel = git.get_root()
|
||||
os.chdir(toplevel)
|
||||
|
||||
args.config = os.path.relpath(args.config)
|
||||
if args.command in {'run', 'try-repo'}:
|
||||
args.files = [os.path.relpath(filename) for filename in args.files]
|
||||
args.files = [_canon_relpath(filename, toplevel)
|
||||
for filename in args.files]
|
||||
if args.command == 'try-repo' and os.path.exists(args.repo):
|
||||
args.repo = os.path.relpath(args.repo)
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue