# Path: pre_commit/parse_shebang.py
# class ExecutableNotFoundError(OSError):
#     def to_output(self) -> tuple[int, bytes, None]:
# def parse_filename(filename: str) -> tuple[str, ...]:
# def find_executable(
#         exe: str, _environ: Mapping[str, str] | None = None,
# ) -> str | None:
# def normexe(orig: str) -> str:
#     def _error(msg: str) -> NoReturn:
# def normalize_cmd(cmd: tuple[str, ...]) -> tuple[str, ...]:
# 
# Path: pre_commit/envcontext.py
# @contextlib.contextmanager
# def envcontext(
#         patch: PatchesT,
#         _env: MutableMapping[str, str] | None = None,
# ) -> Generator[None, None, None]:
#     """In this context, `os.environ` is modified according to `patch`.
# 
#     `patch` is an iterable of 2-tuples (key, value):
#         `key`: string
#         `value`:
#             - string: `environ[key] == value` inside the context.
#             - UNSET: `key not in environ` inside the context.
#             - template: A template is a tuple of strings and Var which will be
#               replaced with the previous environment
#     """
#     env = os.environ if _env is None else _env
#     before = dict(env)
# 
#     for k, v in patch:
#         if v is UNSET:
#             env.pop(k, None)
#         elif isinstance(v, tuple):
#             env[k] = format_env(v, before)
#         else:
#             env[k] = v
# 
#     try:
#         yield
#     finally:
#         env.clear()
#         env.update(before)
# 
# Path: pre_commit/envcontext.py
# class Var(NamedTuple):
#     name: str
#     default: str = ''
# 
# Path: pre_commit/util.py
# def make_executable(filename: str) -> None:
#     original_mode = os.stat(filename).st_mode
#     new_mode = original_mode | stat.S_IXUSR | stat.S_IXGRP | stat.S_IXOTH
#     os.chmod(filename, new_mode)


import contextlib
import os.path
import shutil
import sys
import pytest
from pre_commit import parse_shebang
from pre_commit.envcontext import envcontext
from pre_commit.envcontext import Var
from pre_commit.util import make_executable
    x = tmpdir.join('f')
    x.write('#!/usr/bin/env echo')
    make_executable(x.strpath)
    assert parse_shebang.parse_filename(x.strpath) == ('echo',)


def test_find_executable_full_path():
    assert parse_shebang.find_executable(sys.executable) == sys.executable


def test_find_executable_on_path():
    assert parse_shebang.find_executable('echo') == _echo_exe()


def test_find_executable_not_found_none():
    assert parse_shebang.find_executable('not-a-real-executable') is None


def write_executable(shebang, filename='run'):
    os.mkdir('bin')
    path = os.path.join('bin', filename)
    with open(path, 'w') as f:
        f.write(f'#!{shebang}')
    make_executable(path)
    return path


@contextlib.contextmanager
def bin_on_path():
    bindir = os.path.join(os.getcwd(), 'bin')

# Path: pre_commit/parse_shebang.py
# class ExecutableNotFoundError(OSError):
#     def to_output(self) -> tuple[int, bytes, None]:
# def parse_filename(filename: str) -> tuple[str, ...]:
# def find_executable(
#         exe: str, _environ: Mapping[str, str] | None = None,
# ) -> str | None:
# def normexe(orig: str) -> str:
#     def _error(msg: str) -> NoReturn:
# def normalize_cmd(cmd: tuple[str, ...]) -> tuple[str, ...]:
# 
# Path: pre_commit/envcontext.py
# @contextlib.contextmanager
# def envcontext(
#         patch: PatchesT,
#         _env: MutableMapping[str, str] | None = None,
# ) -> Generator[None, None, None]:
#     """In this context, `os.environ` is modified according to `patch`.
# 
#     `patch` is an iterable of 2-tuples (key, value):
#         `key`: string
#         `value`:
#             - string: `environ[key] == value` inside the context.
#             - UNSET: `key not in environ` inside the context.
#             - template: A template is a tuple of strings and Var which will be
#               replaced with the previous environment
#     """
#     env = os.environ if _env is None else _env
#     before = dict(env)
# 
#     for k, v in patch:
#         if v is UNSET:
#             env.pop(k, None)
#         elif isinstance(v, tuple):
#             env[k] = format_env(v, before)
#         else:
#             env[k] = v
# 
#     try:
#         yield
#     finally:
#         env.clear()
#         env.update(before)
# 
# Path: pre_commit/envcontext.py
# class Var(NamedTuple):
#     name: str
#     default: str = ''
# 
# Path: pre_commit/util.py
# def make_executable(filename: str) -> None:
#     original_mode = os.stat(filename).st_mode
#     new_mode = original_mode | stat.S_IXUSR | stat.S_IXGRP | stat.S_IXOTH
#     os.chmod(filename, new_mode)


# Path: tests/parse_shebang_test.py
import contextlib
import os.path
import shutil
import sys
import pytest
from pre_commit import parse_shebang
from pre_commit.envcontext import envcontext
from pre_commit.envcontext import Var
from pre_commit.util import make_executable

    x = tmpdir.join('f')
    x.write('#!/usr/bin/env echo')
    make_executable(x.strpath)
    assert parse_shebang.parse_filename(x.strpath) == ('echo',)


def test_find_executable_full_path():
    assert parse_shebang.find_executable(sys.executable) == sys.executable


def test_find_executable_on_path():
    assert parse_shebang.find_executable('echo') == _echo_exe()


def test_find_executable_not_found_none():
    assert parse_shebang.find_executable('not-a-real-executable') is None


def write_executable(shebang, filename='run'):
    os.mkdir('bin')
    path = os.path.join('bin', filename)
    with open(path, 'w') as f:
        f.write(f'#!{shebang}')
    make_executable(path)
    return path


@contextlib.contextmanager
def bin_on_path():
    bindir = os.path.join(os.getcwd(), 'bin')

    with envcontext((('PATH', (bindir, os.pathsep, Var('PATH'))),)):