POC or MVP: Succeeds checking shfmt on Windows which uses bash. Requires that bash is meaningful (WSL, MSys64) on the command prompt, and shfmt is installed in the bash environment.

This commit is contained in:
Kees Valkhof 2019-11-25 15:40:48 +01:00
parent 023b337ff0
commit e7698cdb38
4 changed files with 102 additions and 2 deletions

View file

@ -40,3 +40,11 @@ repos:
hooks:
- id: check-hooks-apply
- id: check-useless-excludes
# Requires to be run under `bash`.
# Requires installation of additional tools. Tools are available on Windows.
# shfmt: https://github.com/mvdan/sh/releases
- repo: https://github.com/syntaqx/git-hooks
rev: v0.0.16
hooks:
- id: shfmt
args: [-i 4, -w, -s]

2
bash_script.sh Normal file
View file

@ -0,0 +1,2 @@
#!/bin/bash
set -Eeuo pipefail

View file

@ -0,0 +1,85 @@
#!/usr/bin/env python3
"""."""
import glob
import os
import pathlib
import re
import subprocess
import sys
GLOB_PATTERN = re.compile(r'([^:/\\])(?=[/\\]|$)')
def GetRealCasePath(path):
"""Convert a case preserving path to a case sensitive compatible path."""
drive, tail = os.path.splitdrive(path)
return next(
iter(glob.glob(''.join((drive, re.sub(GLOB_PATTERN, r'[\1]', tail))))),
path,
)
def ConvertPath(path, prefix, drive_letter_case):
"""Convert a Windows path to a POSIX path."""
if os.path.exists(path):
path = GetRealCasePath(path)
drive, tail = os.path.splitdrive(path)
if drive and not os.path.isabs(path):
drive, tail = os.path.splitdrive(os.path.abspath(path))
if drive and drive[1:2] == r':':
path = (
prefix /
drive_letter_case(drive[0]) /
pathlib.PureWindowsPath(tail[1:]).as_posix()
).as_posix()
else:
path = pathlib.PureWindowsPath(path).as_posix()
return path
def ConvertArgsWin32(*args):
"""Convert all path like arguments from Windows to POSIX."""
path = os.path.abspath(os.environ.get('SystemRoot'))
if not path or path[1:2] != r':':
return args
try:
nix_path = subprocess.run(
[args[0], '-c', 'pwd'],
check=True,
cwd=path,
stdout=subprocess.PIPE,
universal_newlines=True,
).stdout.strip()
except Exception:
return args
path = pathlib.PureWindowsPath(
os.path.splitdrive(GetRealCasePath(path))[1],
).as_posix()
prefix, nix_path, tail = (
pathlib.PurePosixPath(nix_path).as_posix().partition(path)
)
if not prefix or nix_path != path or tail:
return args
drive_letter_case = (
(lambda s: s.upper())
if prefix[-1:].isupper()
else (lambda s: s.lower())
if prefix[-1:].islower()
else (lambda s: s)
)
prefix = pathlib.PurePosixPath(prefix[0:-1])
return [args[0]] + [
ConvertPath(arg, prefix, drive_letter_case) for arg in args[1:]
]
ConvertArgs = (
ConvertArgsWin32 if sys.platform == 'win32' else (lambda *args: args)
)
if __name__ == '__main__':
print(*ConvertArgs(*sys.argv[1:]))

View file

@ -4,6 +4,9 @@ from __future__ import unicode_literals
import os.path
from identify.identify import parse_shebang_from_file
from identify.identify import tags_from_path
from pre_commit import ShelPathConv
class ExecutableNotFoundError(OSError):
@ -71,10 +74,12 @@ def normalize_cmd(cmd):
# Use PATH to determine the executable
exe = normexe(cmd[0])
convert = 'shell' in tags_from_path(exe)
# Figure out the shebang from the resulting command
cmd = parse_filename(exe) + (exe,) + cmd[1:]
# This could have given us back another bare executable
exe = normexe(cmd[0])
return (exe,) + cmd[1:]
cmd = (exe,) + cmd[1:]
return ShelPathConv.ConvertArgs(*cmd) if convert else cmd