We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
pip install crashes can easily confuse newbies
those that are not familiar with the usual annoying messaging that pip presents can get pretty easily confused by the output that happens when `pip` fails to install

here's an example:

```console
$ pre-commit run flake8 --all-files
[INFO] Initializing environment for https://gitlab.com/pycqa/flake8:flake8-walrus.
[INFO] Installing environment for https://gitlab.com/pycqa/flake8.
[INFO] Once installed this environment will be reused.
[INFO] This may take a few minutes...
An unexpected error has occurred: CalledProcessError: Command: ('/home/asottile/.cache/pre-commit/repoi6ij0tyu/py_env-python3/bin/python', '/home/asottile/.cache/pre-commit/repoi6ij0tyu/py_env-python3/bin/pip', 'install', '.', 'flake8-walrus')
Return code: 1
Expected return code: 0
Output: 
    Processing /home/asottile/.cache/pre-commit/repoi6ij0tyu
    Collecting flake8-walrus
    
Errors: 
      ERROR: Could not find a version that satisfies the requirement flake8-walrus (from versions: none)
    ERROR: No matching distribution found for flake8-walrus
    WARNING: You are using pip version 19.2.3, however version 19.3.1 is available.
    You should consider upgrading via the 'pip install --upgrade pip' command.
    
Check the log at /home/asottile/.cache/pre-commit/pre-commit.log
```

this ~admittedly is a bit garbled for a number of reasons:
- pip's error message here isn't great (it _could_ say something about `python_requires` or that there are versions available for other versions) **(the actual error is that the python is python3.6 and the plugin requires python3.8)**
- pip is out of date (when is it not? but admittedly who cares) -- **this is what a lot of people try and fix** -- unfortunately there's not really anything to fix here, the version of `pip` is from inside the virtualenv and doesn't really matter all that much
- `pre-commit` is currently splitting the output from stdout and stderr making it harder to read what's going on

I can't really fix the first one, and the second one I could silence but it doesn't quite feel like the right thing to do (and admittedly knowing the pip version is sometimes useful when debugging).  The third however I can pretty easily fix!

--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `pre_commit/util.py`
Content:
```
1 from __future__ import unicode_literals
2 
3 import contextlib
4 import errno
5 import os.path
6 import shutil
7 import stat
8 import subprocess
9 import sys
10 import tempfile
11 
12 import six
13 
14 from pre_commit import five
15 from pre_commit import parse_shebang
16 
17 if sys.version_info >= (3, 7):  # pragma: no cover (PY37+)
18     from importlib.resources import open_binary
19     from importlib.resources import read_text
20 else:  # pragma: no cover (<PY37)
21     from importlib_resources import open_binary
22     from importlib_resources import read_text
23 
24 
25 def mkdirp(path):
26     try:
27         os.makedirs(path)
28     except OSError:
29         if not os.path.exists(path):
30             raise
31 
32 
33 @contextlib.contextmanager
34 def clean_path_on_failure(path):
35     """Cleans up the directory on an exceptional failure."""
36     try:
37         yield
38     except BaseException:
39         if os.path.exists(path):
40             rmtree(path)
41         raise
42 
43 
44 @contextlib.contextmanager
45 def noop_context():
46     yield
47 
48 
49 @contextlib.contextmanager
50 def tmpdir():
51     """Contextmanager to create a temporary directory.  It will be cleaned up
52     afterwards.
53     """
54     tempdir = tempfile.mkdtemp()
55     try:
56         yield tempdir
57     finally:
58         rmtree(tempdir)
59 
60 
61 def resource_bytesio(filename):
62     return open_binary('pre_commit.resources', filename)
63 
64 
65 def resource_text(filename):
66     return read_text('pre_commit.resources', filename)
67 
68 
69 def make_executable(filename):
70     original_mode = os.stat(filename).st_mode
71     os.chmod(
72         filename, original_mode | stat.S_IXUSR | stat.S_IXGRP | stat.S_IXOTH,
73     )
74 
75 
76 class CalledProcessError(RuntimeError):
77     def __init__(self, returncode, cmd, expected_returncode, output=None):
78         super(CalledProcessError, self).__init__(
79             returncode, cmd, expected_returncode, output,
80         )
81         self.returncode = returncode
82         self.cmd = cmd
83         self.expected_returncode = expected_returncode
84         self.output = output
85 
86     def to_bytes(self):
87         output = []
88         for maybe_text in self.output:
89             if maybe_text:
90                 output.append(
91                     b'\n    ' +
92                     five.to_bytes(maybe_text).replace(b'\n', b'\n    '),
93                 )
94             else:
95                 output.append(b'(none)')
96 
97         return b''.join((
98             five.to_bytes(
99                 'Command: {!r}\n'
100                 'Return code: {}\n'
101                 'Expected return code: {}\n'.format(
102                     self.cmd, self.returncode, self.expected_returncode,
103                 ),
104             ),
105             b'Output: ', output[0], b'\n',
106             b'Errors: ', output[1],
107         ))
108 
109     def to_text(self):
110         return self.to_bytes().decode('UTF-8')
111 
112     if six.PY2:  # pragma: no cover (py2)
113         __str__ = to_bytes
114         __unicode__ = to_text
115     else:  # pragma: no cover (py3)
116         __bytes__ = to_bytes
117         __str__ = to_text
118 
119 
120 def _cmd_kwargs(*cmd, **kwargs):
121     # py2/py3 on windows are more strict about the types here
122     cmd = tuple(five.n(arg) for arg in cmd)
123     kwargs['env'] = {
124         five.n(key): five.n(value)
125         for key, value in kwargs.pop('env', {}).items()
126     } or None
127     for arg in ('stdin', 'stdout', 'stderr'):
128         kwargs.setdefault(arg, subprocess.PIPE)
129     return cmd, kwargs
130 
131 
132 def cmd_output_b(*cmd, **kwargs):
133     retcode = kwargs.pop('retcode', 0)
134     cmd, kwargs = _cmd_kwargs(*cmd, **kwargs)
135 
136     try:
137         cmd = parse_shebang.normalize_cmd(cmd)
138     except parse_shebang.ExecutableNotFoundError as e:
139         returncode, stdout_b, stderr_b = e.to_output()
140     else:
141         proc = subprocess.Popen(cmd, **kwargs)
142         stdout_b, stderr_b = proc.communicate()
143         returncode = proc.returncode
144 
145     if retcode is not None and retcode != returncode:
146         raise CalledProcessError(
147             returncode, cmd, retcode, output=(stdout_b, stderr_b),
148         )
149 
150     return returncode, stdout_b, stderr_b
151 
152 
153 def cmd_output(*cmd, **kwargs):
154     returncode, stdout_b, stderr_b = cmd_output_b(*cmd, **kwargs)
155     stdout = stdout_b.decode('UTF-8') if stdout_b is not None else None
156     stderr = stderr_b.decode('UTF-8') if stderr_b is not None else None
157     return returncode, stdout, stderr
158 
159 
160 if os.name != 'nt':  # pragma: windows no cover
161     from os import openpty
162     import termios
163 
164     class Pty(object):
165         def __init__(self):
166             self.r = self.w = None
167 
168         def __enter__(self):
169             self.r, self.w = openpty()
170 
171             # tty flags normally change \n to \r\n
172             attrs = termios.tcgetattr(self.r)
173             attrs[1] &= ~(termios.ONLCR | termios.OPOST)
174             termios.tcsetattr(self.r, termios.TCSANOW, attrs)
175 
176             return self
177 
178         def close_w(self):
179             if self.w is not None:
180                 os.close(self.w)
181                 self.w = None
182 
183         def close_r(self):
184             assert self.r is not None
185             os.close(self.r)
186             self.r = None
187 
188         def __exit__(self, exc_type, exc_value, traceback):
189             self.close_w()
190             self.close_r()
191 
192     def cmd_output_p(*cmd, **kwargs):
193         assert kwargs.pop('retcode') is None
194         assert kwargs['stderr'] == subprocess.STDOUT, kwargs['stderr']
195         cmd, kwargs = _cmd_kwargs(*cmd, **kwargs)
196 
197         try:
198             cmd = parse_shebang.normalize_cmd(cmd)
199         except parse_shebang.ExecutableNotFoundError as e:
200             return e.to_output()
201 
202         with open(os.devnull) as devnull, Pty() as pty:
203             kwargs.update({'stdin': devnull, 'stdout': pty.w, 'stderr': pty.w})
204             proc = subprocess.Popen(cmd, **kwargs)
205             pty.close_w()
206 
207             buf = b''
208             while True:
209                 try:
210                     bts = os.read(pty.r, 4096)
211                 except OSError as e:
212                     if e.errno == errno.EIO:
213                         bts = b''
214                     else:
215                         raise
216                 else:
217                     buf += bts
218                 if not bts:
219                     break
220 
221         return proc.wait(), buf, None
222 else:  # pragma: no cover
223     cmd_output_p = cmd_output_b
224 
225 
226 def rmtree(path):
227     """On windows, rmtree fails for readonly dirs."""
228     def handle_remove_readonly(func, path, exc):
229         excvalue = exc[1]
230         if (
231                 func in (os.rmdir, os.remove, os.unlink) and
232                 excvalue.errno == errno.EACCES
233         ):
234             for p in (path, os.path.dirname(path)):
235                 os.chmod(p, os.stat(p).st_mode | stat.S_IWUSR)
236             func(path)
237         else:
238             raise
239     shutil.rmtree(path, ignore_errors=False, onerror=handle_remove_readonly)
240 
241 
242 def parse_version(s):
243     """poor man's version comparison"""
244     return tuple(int(p) for p in s.split('.'))
245
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/pre_commit/util.py b/pre_commit/util.py
--- a/pre_commit/util.py
+++ b/pre_commit/util.py
@@ -74,36 +74,31 @@
 
 
 class CalledProcessError(RuntimeError):
-    def __init__(self, returncode, cmd, expected_returncode, output=None):
+    def __init__(self, returncode, cmd, expected_returncode, stdout, stderr):
         super(CalledProcessError, self).__init__(
-            returncode, cmd, expected_returncode, output,
+            returncode, cmd, expected_returncode, stdout, stderr,
         )
         self.returncode = returncode
         self.cmd = cmd
         self.expected_returncode = expected_returncode
-        self.output = output
+        self.stdout = stdout
+        self.stderr = stderr
 
     def to_bytes(self):
-        output = []
-        for maybe_text in self.output:
-            if maybe_text:
-                output.append(
-                    b'\n    ' +
-                    five.to_bytes(maybe_text).replace(b'\n', b'\n    '),
-                )
+        def _indent_or_none(part):
+            if part:
+                return b'\n    ' + part.replace(b'\n', b'\n    ')
             else:
-                output.append(b'(none)')
+                return b' (none)'
 
         return b''.join((
-            five.to_bytes(
-                'Command: {!r}\n'
-                'Return code: {}\n'
-                'Expected return code: {}\n'.format(
-                    self.cmd, self.returncode, self.expected_returncode,
-                ),
-            ),
-            b'Output: ', output[0], b'\n',
-            b'Errors: ', output[1],
+            'command: {!r}\n'
+            'return code: {}\n'
+            'expected return code: {}\n'.format(
+                self.cmd, self.returncode, self.expected_returncode,
+            ).encode('UTF-8'),
+            b'stdout:', _indent_or_none(self.stdout), b'\n',
+            b'stderr:', _indent_or_none(self.stderr),
         ))
 
     def to_text(self):
@@ -143,9 +138,7 @@
         returncode = proc.returncode
 
     if retcode is not None and retcode != returncode:
-        raise CalledProcessError(
-            returncode, cmd, retcode, output=(stdout_b, stderr_b),
-        )
+        raise CalledProcessError(returncode, cmd, retcode, stdout_b, stderr_b)
 
     return returncode, stdout_b, stderr_b

{"golden_diff": "diff --git a/pre_commit/util.py b/pre_commit/util.py\n--- a/pre_commit/util.py\n+++ b/pre_commit/util.py\n@@ -74,36 +74,31 @@\n \n \n class CalledProcessError(RuntimeError):\n-    def __init__(self, returncode, cmd, expected_returncode, output=None):\n+    def __init__(self, returncode, cmd, expected_returncode, stdout, stderr):\n         super(CalledProcessError, self).__init__(\n-            returncode, cmd, expected_returncode, output,\n+            returncode, cmd, expected_returncode, stdout, stderr,\n         )\n         self.returncode = returncode\n         self.cmd = cmd\n         self.expected_returncode = expected_returncode\n-        self.output = output\n+        self.stdout = stdout\n+        self.stderr = stderr\n \n     def to_bytes(self):\n-        output = []\n-        for maybe_text in self.output:\n-            if maybe_text:\n-                output.append(\n-                    b'\\n    ' +\n-                    five.to_bytes(maybe_text).replace(b'\\n', b'\\n    '),\n-                )\n+        def _indent_or_none(part):\n+            if part:\n+                return b'\\n    ' + part.replace(b'\\n', b'\\n    ')\n             else:\n-                output.append(b'(none)')\n+                return b' (none)'\n \n         return b''.join((\n-            five.to_bytes(\n-                'Command: {!r}\\n'\n-                'Return code: {}\\n'\n-                'Expected return code: {}\\n'.format(\n-                    self.cmd, self.returncode, self.expected_returncode,\n-                ),\n-            ),\n-            b'Output: ', output[0], b'\\n',\n-            b'Errors: ', output[1],\n+            'command: {!r}\\n'\n+            'return code: {}\\n'\n+            'expected return code: {}\\n'.format(\n+                self.cmd, self.returncode, self.expected_returncode,\n+            ).encode('UTF-8'),\n+            b'stdout:', _indent_or_none(self.stdout), b'\\n',\n+            b'stderr:', _indent_or_none(self.stderr),\n         ))\n \n     def to_text(self):\n@@ -143,9 +138,7 @@\n         returncode = proc.returncode\n \n     if retcode is not None and retcode != returncode:\n-        raise CalledProcessError(\n-            returncode, cmd, retcode, output=(stdout_b, stderr_b),\n-        )\n+        raise CalledProcessError(returncode, cmd, retcode, stdout_b, stderr_b)\n \n     return returncode, stdout_b, stderr_b\n", "issue": "pip install crashes can easily confuse newbies\nthose that are not familiar with the usual annoying messaging that pip presents can get pretty easily confused by the output that happens when `pip` fails to install\r\n\r\nhere's an example:\r\n\r\n```console\r\n$ pre-commit run flake8 --all-files\r\n[INFO] Initializing environment for https://gitlab.com/pycqa/flake8:flake8-walrus.\r\n[INFO] Installing environment for https://gitlab.com/pycqa/flake8.\r\n[INFO] Once installed this environment will be reused.\r\n[INFO] This may take a few minutes...\r\nAn unexpected error has occurred: CalledProcessError: Command: ('/home/asottile/.cache/pre-commit/repoi6ij0tyu/py_env-python3/bin/python', '/home/asottile/.cache/pre-commit/repoi6ij0tyu/py_env-python3/bin/pip', 'install', '.', 'flake8-walrus')\r\nReturn code: 1\r\nExpected return code: 0\r\nOutput: \r\n    Processing /home/asottile/.cache/pre-commit/repoi6ij0tyu\r\n    Collecting flake8-walrus\r\n    \r\nErrors: \r\n      ERROR: Could not find a version that satisfies the requirement flake8-walrus (from versions: none)\r\n    ERROR: No matching distribution found for flake8-walrus\r\n    WARNING: You are using pip version 19.2.3, however version 19.3.1 is available.\r\n    You should consider upgrading via the 'pip install --upgrade pip' command.\r\n    \r\nCheck the log at /home/asottile/.cache/pre-commit/pre-commit.log\r\n```\r\n\r\nthis ~admittedly is a bit garbled for a number of reasons:\r\n- pip's error message here isn't great (it _could_ say something about `python_requires` or that there are versions available for other versions) **(the actual error is that the python is python3.6 and the plugin requires python3.8)**\r\n- pip is out of date (when is it not? but admittedly who cares) -- **this is what a lot of people try and fix** -- unfortunately there's not really anything to fix here, the version of `pip` is from inside the virtualenv and doesn't really matter all that much\r\n- `pre-commit` is currently splitting the output from stdout and stderr making it harder to read what's going on\r\n\r\nI can't really fix the first one, and the second one I could silence but it doesn't quite feel like the right thing to do (and admittedly knowing the pip version is sometimes useful when debugging).  The third however I can pretty easily fix!\n", "before_files": [{"content": "from __future__ import unicode_literals\n\nimport contextlib\nimport errno\nimport os.path\nimport shutil\nimport stat\nimport subprocess\nimport sys\nimport tempfile\n\nimport six\n\nfrom pre_commit import five\nfrom pre_commit import parse_shebang\n\nif sys.version_info >= (3, 7):  # pragma: no cover (PY37+)\n    from importlib.resources import open_binary\n    from importlib.resources import read_text\nelse:  # pragma: no cover (<PY37)\n    from importlib_resources import open_binary\n    from importlib_resources import read_text\n\n\ndef mkdirp(path):\n    try:\n        os.makedirs(path)\n    except OSError:\n        if not os.path.exists(path):\n            raise\n\n\n@contextlib.contextmanager\ndef clean_path_on_failure(path):\n    \"\"\"Cleans up the directory on an exceptional failure.\"\"\"\n    try:\n        yield\n    except BaseException:\n        if os.path.exists(path):\n            rmtree(path)\n        raise\n\n\n@contextlib.contextmanager\ndef noop_context():\n    yield\n\n\n@contextlib.contextmanager\ndef tmpdir():\n    \"\"\"Contextmanager to create a temporary directory.  It will be cleaned up\n    afterwards.\n    \"\"\"\n    tempdir = tempfile.mkdtemp()\n    try:\n        yield tempdir\n    finally:\n        rmtree(tempdir)\n\n\ndef resource_bytesio(filename):\n    return open_binary('pre_commit.resources', filename)\n\n\ndef resource_text(filename):\n    return read_text('pre_commit.resources', filename)\n\n\ndef make_executable(filename):\n    original_mode = os.stat(filename).st_mode\n    os.chmod(\n        filename, original_mode | stat.S_IXUSR | stat.S_IXGRP | stat.S_IXOTH,\n    )\n\n\nclass CalledProcessError(RuntimeError):\n    def __init__(self, returncode, cmd, expected_returncode, output=None):\n        super(CalledProcessError, self).__init__(\n            returncode, cmd, expected_returncode, output,\n        )\n        self.returncode = returncode\n        self.cmd = cmd\n        self.expected_returncode = expected_returncode\n        self.output = output\n\n    def to_bytes(self):\n        output = []\n        for maybe_text in self.output:\n            if maybe_text:\n                output.append(\n                    b'\\n    ' +\n                    five.to_bytes(maybe_text).replace(b'\\n', b'\\n    '),\n                )\n            else:\n                output.append(b'(none)')\n\n        return b''.join((\n            five.to_bytes(\n                'Command: {!r}\\n'\n                'Return code: {}\\n'\n                'Expected return code: {}\\n'.format(\n                    self.cmd, self.returncode, self.expected_returncode,\n                ),\n            ),\n            b'Output: ', output[0], b'\\n',\n            b'Errors: ', output[1],\n        ))\n\n    def to_text(self):\n        return self.to_bytes().decode('UTF-8')\n\n    if six.PY2:  # pragma: no cover (py2)\n        __str__ = to_bytes\n        __unicode__ = to_text\n    else:  # pragma: no cover (py3)\n        __bytes__ = to_bytes\n        __str__ = to_text\n\n\ndef _cmd_kwargs(*cmd, **kwargs):\n    # py2/py3 on windows are more strict about the types here\n    cmd = tuple(five.n(arg) for arg in cmd)\n    kwargs['env'] = {\n        five.n(key): five.n(value)\n        for key, value in kwargs.pop('env', {}).items()\n    } or None\n    for arg in ('stdin', 'stdout', 'stderr'):\n        kwargs.setdefault(arg, subprocess.PIPE)\n    return cmd, kwargs\n\n\ndef cmd_output_b(*cmd, **kwargs):\n    retcode = kwargs.pop('retcode', 0)\n    cmd, kwargs = _cmd_kwargs(*cmd, **kwargs)\n\n    try:\n        cmd = parse_shebang.normalize_cmd(cmd)\n    except parse_shebang.ExecutableNotFoundError as e:\n        returncode, stdout_b, stderr_b = e.to_output()\n    else:\n        proc = subprocess.Popen(cmd, **kwargs)\n        stdout_b, stderr_b = proc.communicate()\n        returncode = proc.returncode\n\n    if retcode is not None and retcode != returncode:\n        raise CalledProcessError(\n            returncode, cmd, retcode, output=(stdout_b, stderr_b),\n        )\n\n    return returncode, stdout_b, stderr_b\n\n\ndef cmd_output(*cmd, **kwargs):\n    returncode, stdout_b, stderr_b = cmd_output_b(*cmd, **kwargs)\n    stdout = stdout_b.decode('UTF-8') if stdout_b is not None else None\n    stderr = stderr_b.decode('UTF-8') if stderr_b is not None else None\n    return returncode, stdout, stderr\n\n\nif os.name != 'nt':  # pragma: windows no cover\n    from os import openpty\n    import termios\n\n    class Pty(object):\n        def __init__(self):\n            self.r = self.w = None\n\n        def __enter__(self):\n            self.r, self.w = openpty()\n\n            # tty flags normally change \\n to \\r\\n\n            attrs = termios.tcgetattr(self.r)\n            attrs[1] &= ~(termios.ONLCR | termios.OPOST)\n            termios.tcsetattr(self.r, termios.TCSANOW, attrs)\n\n            return self\n\n        def close_w(self):\n            if self.w is not None:\n                os.close(self.w)\n                self.w = None\n\n        def close_r(self):\n            assert self.r is not None\n            os.close(self.r)\n            self.r = None\n\n        def __exit__(self, exc_type, exc_value, traceback):\n            self.close_w()\n            self.close_r()\n\n    def cmd_output_p(*cmd, **kwargs):\n        assert kwargs.pop('retcode') is None\n        assert kwargs['stderr'] == subprocess.STDOUT, kwargs['stderr']\n        cmd, kwargs = _cmd_kwargs(*cmd, **kwargs)\n\n        try:\n            cmd = parse_shebang.normalize_cmd(cmd)\n        except parse_shebang.ExecutableNotFoundError as e:\n            return e.to_output()\n\n        with open(os.devnull) as devnull, Pty() as pty:\n            kwargs.update({'stdin': devnull, 'stdout': pty.w, 'stderr': pty.w})\n            proc = subprocess.Popen(cmd, **kwargs)\n            pty.close_w()\n\n            buf = b''\n            while True:\n                try:\n                    bts = os.read(pty.r, 4096)\n                except OSError as e:\n                    if e.errno == errno.EIO:\n                        bts = b''\n                    else:\n                        raise\n                else:\n                    buf += bts\n                if not bts:\n                    break\n\n        return proc.wait(), buf, None\nelse:  # pragma: no cover\n    cmd_output_p = cmd_output_b\n\n\ndef rmtree(path):\n    \"\"\"On windows, rmtree fails for readonly dirs.\"\"\"\n    def handle_remove_readonly(func, path, exc):\n        excvalue = exc[1]\n        if (\n                func in (os.rmdir, os.remove, os.unlink) and\n                excvalue.errno == errno.EACCES\n        ):\n            for p in (path, os.path.dirname(path)):\n                os.chmod(p, os.stat(p).st_mode | stat.S_IWUSR)\n            func(path)\n        else:\n            raise\n    shutil.rmtree(path, ignore_errors=False, onerror=handle_remove_readonly)\n\n\ndef parse_version(s):\n    \"\"\"poor man's version comparison\"\"\"\n    return tuple(int(p) for p in s.split('.'))\n", "path": "pre_commit/util.py"}], "after_files": [{"content": "from __future__ import unicode_literals\n\nimport contextlib\nimport errno\nimport os.path\nimport shutil\nimport stat\nimport subprocess\nimport sys\nimport tempfile\n\nimport six\n\nfrom pre_commit import five\nfrom pre_commit import parse_shebang\n\nif sys.version_info >= (3, 7):  # pragma: no cover (PY37+)\n    from importlib.resources import open_binary\n    from importlib.resources import read_text\nelse:  # pragma: no cover (<PY37)\n    from importlib_resources import open_binary\n    from importlib_resources import read_text\n\n\ndef mkdirp(path):\n    try:\n        os.makedirs(path)\n    except OSError:\n        if not os.path.exists(path):\n            raise\n\n\n@contextlib.contextmanager\ndef clean_path_on_failure(path):\n    \"\"\"Cleans up the directory on an exceptional failure.\"\"\"\n    try:\n        yield\n    except BaseException:\n        if os.path.exists(path):\n            rmtree(path)\n        raise\n\n\n@contextlib.contextmanager\ndef noop_context():\n    yield\n\n\n@contextlib.contextmanager\ndef tmpdir():\n    \"\"\"Contextmanager to create a temporary directory.  It will be cleaned up\n    afterwards.\n    \"\"\"\n    tempdir = tempfile.mkdtemp()\n    try:\n        yield tempdir\n    finally:\n        rmtree(tempdir)\n\n\ndef resource_bytesio(filename):\n    return open_binary('pre_commit.resources', filename)\n\n\ndef resource_text(filename):\n    return read_text('pre_commit.resources', filename)\n\n\ndef make_executable(filename):\n    original_mode = os.stat(filename).st_mode\n    os.chmod(\n        filename, original_mode | stat.S_IXUSR | stat.S_IXGRP | stat.S_IXOTH,\n    )\n\n\nclass CalledProcessError(RuntimeError):\n    def __init__(self, returncode, cmd, expected_returncode, stdout, stderr):\n        super(CalledProcessError, self).__init__(\n            returncode, cmd, expected_returncode, stdout, stderr,\n        )\n        self.returncode = returncode\n        self.cmd = cmd\n        self.expected_returncode = expected_returncode\n        self.stdout = stdout\n        self.stderr = stderr\n\n    def to_bytes(self):\n        def _indent_or_none(part):\n            if part:\n                return b'\\n    ' + part.replace(b'\\n', b'\\n    ')\n            else:\n                return b' (none)'\n\n        return b''.join((\n            'command: {!r}\\n'\n            'return code: {}\\n'\n            'expected return code: {}\\n'.format(\n                self.cmd, self.returncode, self.expected_returncode,\n            ).encode('UTF-8'),\n            b'stdout:', _indent_or_none(self.stdout), b'\\n',\n            b'stderr:', _indent_or_none(self.stderr),\n        ))\n\n    def to_text(self):\n        return self.to_bytes().decode('UTF-8')\n\n    if six.PY2:  # pragma: no cover (py2)\n        __str__ = to_bytes\n        __unicode__ = to_text\n    else:  # pragma: no cover (py3)\n        __bytes__ = to_bytes\n        __str__ = to_text\n\n\ndef _cmd_kwargs(*cmd, **kwargs):\n    # py2/py3 on windows are more strict about the types here\n    cmd = tuple(five.n(arg) for arg in cmd)\n    kwargs['env'] = {\n        five.n(key): five.n(value)\n        for key, value in kwargs.pop('env', {}).items()\n    } or None\n    for arg in ('stdin', 'stdout', 'stderr'):\n        kwargs.setdefault(arg, subprocess.PIPE)\n    return cmd, kwargs\n\n\ndef cmd_output_b(*cmd, **kwargs):\n    retcode = kwargs.pop('retcode', 0)\n    cmd, kwargs = _cmd_kwargs(*cmd, **kwargs)\n\n    try:\n        cmd = parse_shebang.normalize_cmd(cmd)\n    except parse_shebang.ExecutableNotFoundError as e:\n        returncode, stdout_b, stderr_b = e.to_output()\n    else:\n        proc = subprocess.Popen(cmd, **kwargs)\n        stdout_b, stderr_b = proc.communicate()\n        returncode = proc.returncode\n\n    if retcode is not None and retcode != returncode:\n        raise CalledProcessError(returncode, cmd, retcode, stdout_b, stderr_b)\n\n    return returncode, stdout_b, stderr_b\n\n\ndef cmd_output(*cmd, **kwargs):\n    returncode, stdout_b, stderr_b = cmd_output_b(*cmd, **kwargs)\n    stdout = stdout_b.decode('UTF-8') if stdout_b is not None else None\n    stderr = stderr_b.decode('UTF-8') if stderr_b is not None else None\n    return returncode, stdout, stderr\n\n\nif os.name != 'nt':  # pragma: windows no cover\n    from os import openpty\n    import termios\n\n    class Pty(object):\n        def __init__(self):\n            self.r = self.w = None\n\n        def __enter__(self):\n            self.r, self.w = openpty()\n\n            # tty flags normally change \\n to \\r\\n\n            attrs = termios.tcgetattr(self.r)\n            attrs[1] &= ~(termios.ONLCR | termios.OPOST)\n            termios.tcsetattr(self.r, termios.TCSANOW, attrs)\n\n            return self\n\n        def close_w(self):\n            if self.w is not None:\n                os.close(self.w)\n                self.w = None\n\n        def close_r(self):\n            assert self.r is not None\n            os.close(self.r)\n            self.r = None\n\n        def __exit__(self, exc_type, exc_value, traceback):\n            self.close_w()\n            self.close_r()\n\n    def cmd_output_p(*cmd, **kwargs):\n        assert kwargs.pop('retcode') is None\n        assert kwargs['stderr'] == subprocess.STDOUT, kwargs['stderr']\n        cmd, kwargs = _cmd_kwargs(*cmd, **kwargs)\n\n        try:\n            cmd = parse_shebang.normalize_cmd(cmd)\n        except parse_shebang.ExecutableNotFoundError as e:\n            return e.to_output()\n\n        with open(os.devnull) as devnull, Pty() as pty:\n            kwargs.update({'stdin': devnull, 'stdout': pty.w, 'stderr': pty.w})\n            proc = subprocess.Popen(cmd, **kwargs)\n            pty.close_w()\n\n            buf = b''\n            while True:\n                try:\n                    bts = os.read(pty.r, 4096)\n                except OSError as e:\n                    if e.errno == errno.EIO:\n                        bts = b''\n                    else:\n                        raise\n                else:\n                    buf += bts\n                if not bts:\n                    break\n\n        return proc.wait(), buf, None\nelse:  # pragma: no cover\n    cmd_output_p = cmd_output_b\n\n\ndef rmtree(path):\n    \"\"\"On windows, rmtree fails for readonly dirs.\"\"\"\n    def handle_remove_readonly(func, path, exc):\n        excvalue = exc[1]\n        if (\n                func in (os.rmdir, os.remove, os.unlink) and\n                excvalue.errno == errno.EACCES\n        ):\n            for p in (path, os.path.dirname(path)):\n                os.chmod(p, os.stat(p).st_mode | stat.S_IWUSR)\n            func(path)\n        else:\n            raise\n    shutil.rmtree(path, ignore_errors=False, onerror=handle_remove_readonly)\n\n\ndef parse_version(s):\n    \"\"\"poor man's version comparison\"\"\"\n    return tuple(int(p) for p in s.split('.'))\n", "path": "pre_commit/util.py"}]}