We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
pre-commit crashes when running during unresolved merge conflict
I intentionally forced the following by making two branches conflict and then editing a file on that branch.  `pre-commit` should fail-fast in a merge conflict situation.

```
$ git diff --exit-code
diff --cc foo.txt
index 8ff26e7,c148433..0000000
--- a/foo.txt
+++ b/foo.txt
@@@ -1,4 -1,5 +1,11 @@@
  asdf
++<<<<<<< HEAD
 +fdsa
 +yeah
 +yeah
++=======
+ asdf
+ asdf
+ asdf
+ 
++>>>>>>> derp
diff --git a/git_code_debt/generate.py b/git_code_debt/generate.py
index 12ceec6..967506e 100644
--- a/git_code_debt/generate.py
+++ b/git_code_debt/generate.py
@@ -12,6 +12,7 @@ from git_code_debt.logic import get_previous_sha
 from git_code_debt.logic import insert_metric_values
 from git_code_debt.repo_parser import RepoParser

+
 def get_metrics(diff, metric_parsers):
     def get_all_metrics(file_diff_stats):
         for metric_parser_cls in metric_parsers:
(py_env)[anthony@anthony-VirtualBox git-code-debt (herp|MERGING)]$ echo $?
1
(py_env)[anthony@anthony-VirtualBox git-code-debt (herp|MERGING)]$ pre-commit 
[WARNING] Unstaged files detected.
[INFO] Stashing unstaged files to /tmp/git-code-debt/.pre-commit-files/patch1397455577.
Traceback (most recent call last):
  File "/tmp/git-code-debt/py_env/bin/pre-commit", line 9, in <module>
    load_entry_point('pre-commit==0.0.0', 'console_scripts', 'pre-commit')()
  File "/tmp/git-code-debt/py_env/local/lib/python2.7/site-packages/pre_commit/util.py", line 52, in wrapper
    return func(argv)
  File "/tmp/git-code-debt/py_env/local/lib/python2.7/site-packages/pre_commit/run.py", line 59, in run
    return commands.run(runner, args)
  File "/tmp/git-code-debt/py_env/local/lib/python2.7/site-packages/pre_commit/commands.py", line 242, in run
    with ctx:
  File "/usr/lib/python2.7/contextlib.py", line 17, in __enter__
    return self.gen.next()
  File "/tmp/git-code-debt/py_env/local/lib/python2.7/site-packages/pre_commit/staged_files_only.py", line 35, in staged_files_only
    cmd_runner.run(['git', 'checkout', '--', '.'])
  File "/tmp/git-code-debt/py_env/local/lib/python2.7/site-packages/pre_commit/prefixed_command_runner.py", line 77, in run
    returncode, replaced_cmd, retcode, output=(stdout, stderr),
pre_commit.prefixed_command_runner.CalledProcessError: Command: ['git', 'checkout', '--', '.']
Return code: 1
Expected return code: 0
Output: (u'', u"error: path 'foo.txt' is unmerged\n")

(py_env)[anthony@anthony-VirtualBox git-code-debt (herp|MERGING)]$ 
```


--- 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/commands.py`
Content:
```
1 from __future__ import print_function
2 
3 import logging
4 import os
5 import pkg_resources
6 import shutil
7 import stat
8 import subprocess
9 import sys
10 from asottile.ordereddict import OrderedDict
11 from asottile.yaml import ordered_dump
12 from asottile.yaml import ordered_load
13 from plumbum import local
14 
15 import pre_commit.constants as C
16 from pre_commit import git
17 from pre_commit import color
18 from pre_commit.clientlib.validate_config import CONFIG_JSON_SCHEMA
19 from pre_commit.clientlib.validate_config import load_config
20 from pre_commit.jsonschema_extensions import remove_defaults
21 from pre_commit.logging_handler import LoggingHandler
22 from pre_commit.repository import Repository
23 from pre_commit.staged_files_only import staged_files_only
24 from pre_commit.util import noop_context
25 
26 
27 logger = logging.getLogger('pre_commit')
28 
29 COLS = int(subprocess.Popen(['tput', 'cols'], stdout=subprocess.PIPE).communicate()[0])
30 
31 PASS_FAIL_LENGTH = 6
32 
33 
34 def install(runner):
35     """Install the pre-commit hooks."""
36     pre_commit_file = pkg_resources.resource_filename('pre_commit', 'resources/pre-commit.sh')
37     with open(runner.pre_commit_path, 'w') as pre_commit_file_obj:
38         pre_commit_file_obj.write(open(pre_commit_file).read())
39 
40     original_mode = os.stat(runner.pre_commit_path).st_mode
41     os.chmod(
42         runner.pre_commit_path,
43         original_mode | stat.S_IXUSR | stat.S_IXGRP | stat.S_IXOTH,
44     )
45 
46     print('pre-commit installed at {0}'.format(runner.pre_commit_path))
47 
48     return 0
49 
50 
51 def uninstall(runner):
52     """Uninstall the pre-commit hooks."""
53     if os.path.exists(runner.pre_commit_path):
54         os.remove(runner.pre_commit_path)
55         print('pre-commit uninstalled')
56     return 0
57 
58 
59 class RepositoryCannotBeUpdatedError(RuntimeError):
60     pass
61 
62 
63 def _update_repository(repo_config):
64     """Updates a repository to the tip of `master`.  If the repository cannot
65     be updated because a hook that is configured does not exist in `master`,
66     this raises a RepositoryCannotBeUpdatedError
67 
68     Args:
69         repo_config - A config for a repository
70     """
71     repo = Repository(repo_config)
72 
73     with repo.in_checkout():
74         local['git']['fetch']()
75         head_sha = local['git']['rev-parse', 'origin/master']().strip()
76 
77     # Don't bother trying to update if our sha is the same
78     if head_sha == repo_config['sha']:
79         return repo_config
80 
81     # Construct a new config with the head sha
82     new_config = OrderedDict(repo_config)
83     new_config['sha'] = head_sha
84     new_repo = Repository(new_config)
85 
86     # See if any of our hooks were deleted with the new commits
87     hooks = set(repo.hooks.keys())
88     hooks_missing = hooks - (hooks & set(new_repo.manifest.keys()))
89     if hooks_missing:
90         raise RepositoryCannotBeUpdatedError(
91             'Cannot update because the tip of master is missing these hooks:\n'
92             '{0}'.format(', '.join(sorted(hooks_missing)))
93         )
94 
95     return remove_defaults([new_config], CONFIG_JSON_SCHEMA)[0]
96 
97 
98 def autoupdate(runner):
99     """Auto-update the pre-commit config to the latest versions of repos."""
100     retv = 0
101     output_configs = []
102     changed = False
103 
104     input_configs = load_config(
105         runner.config_file_path,
106         load_strategy=ordered_load,
107     )
108 
109     for repo_config in input_configs:
110         print('Updating {0}...'.format(repo_config['repo']), end='')
111         try:
112             new_repo_config = _update_repository(repo_config)
113         except RepositoryCannotBeUpdatedError as error:
114             print(error.args[0])
115             output_configs.append(repo_config)
116             retv = 1
117             continue
118 
119         if new_repo_config['sha'] != repo_config['sha']:
120             changed = True
121             print(
122                 'updating {0} -> {1}.'.format(
123                     repo_config['sha'], new_repo_config['sha'],
124                 )
125             )
126             output_configs.append(new_repo_config)
127         else:
128             print('already up to date.')
129             output_configs.append(repo_config)
130 
131     if changed:
132         with open(runner.config_file_path, 'w') as config_file:
133             config_file.write(
134                 ordered_dump(output_configs, **C.YAML_DUMP_KWARGS)
135             )
136 
137     return retv
138 
139 
140 def clean(runner):
141     if os.path.exists(runner.hooks_workspace_path):
142         shutil.rmtree(runner.hooks_workspace_path)
143         print('Cleaned {0}.'.format(runner.hooks_workspace_path))
144     return 0
145 
146 
147 def _run_single_hook(runner, repository, hook_id, args, write):
148     if args.all_files:
149         get_filenames = git.get_all_files_matching
150     else:
151         get_filenames = git.get_staged_files_matching
152 
153     hook = repository.hooks[hook_id]
154 
155     filenames = get_filenames(hook['files'], hook['exclude'])
156     if not filenames:
157         no_files_msg = '(no files to check) '
158         skipped_msg = 'Skipped'
159         write(
160             '{0}{1}{2}{3}\n'.format(
161                 hook['name'],
162                 '.' * (
163                     COLS -
164                     len(hook['name']) -
165                     len(no_files_msg) -
166                     len(skipped_msg) -
167                     6
168                 ),
169                 no_files_msg,
170                 color.format_color(skipped_msg, color.TURQUOISE, args.color),
171             )
172         )
173         return 0
174 
175     # Print the hook and the dots first in case the hook takes hella long to
176     # run.
177     write(
178         '{0}{1}'.format(
179             hook['name'],
180             '.' * (COLS - len(hook['name']) - PASS_FAIL_LENGTH - 6),
181         ),
182     )
183     sys.stdout.flush()
184 
185     retcode, stdout, stderr = repository.run_hook(
186         runner.cmd_runner,
187         hook_id,
188         filenames,
189     )
190 
191     if retcode != repository.hooks[hook_id]['expected_return_value']:
192         retcode = 1
193         print_color = color.RED
194         pass_fail = 'Failed'
195     else:
196         retcode = 0
197         print_color = color.GREEN
198         pass_fail = 'Passed'
199 
200     write(color.format_color(pass_fail, print_color, args.color) + '\n')
201 
202     if (stdout or stderr) and (retcode or args.verbose):
203         write('\n')
204         for output in (stdout, stderr):
205             if output.strip():
206                 write(output.strip() + '\n')
207         write('\n')
208 
209     return retcode
210 
211 
212 def _run_hooks(runner, args, write):
213     """Actually run the hooks."""
214     retval = 0
215 
216     for repo in runner.repositories:
217         for hook_id in repo.hooks:
218             retval |= _run_single_hook(runner, repo, hook_id, args, write=write)
219 
220     return retval
221 
222 
223 def _run_hook(runner, hook_id, args, write):
224     for repo in runner.repositories:
225         if hook_id in repo.hooks:
226             return _run_single_hook(runner, repo, hook_id, args, write=write)
227     else:
228         write('No hook with id `{0}`\n'.format(hook_id))
229         return 1
230 
231 
232 def run(runner, args, write=sys.stdout.write):
233     # Set up our logging handler
234     logger.addHandler(LoggingHandler(args.color, write=write))
235     logger.setLevel(logging.INFO)
236 
237     if args.no_stash or args.all_files:
238         ctx = noop_context()
239     else:
240         ctx = staged_files_only(runner.cmd_runner)
241 
242     with ctx:
243         if args.hook:
244             return _run_hook(runner, args.hook, args, write=write)
245         else:
246             return _run_hooks(runner, args, write=write)
247
```
--- 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/commands.py b/pre_commit/commands.py
--- a/pre_commit/commands.py
+++ b/pre_commit/commands.py
@@ -229,11 +229,21 @@
         return 1
 
 
+def _has_unmerged_paths(runner):
+    _, stdout, _ = runner.cmd_runner.run(['git', 'ls-files', '--unmerged'])
+    return bool(stdout.strip())
+
+
 def run(runner, args, write=sys.stdout.write):
     # Set up our logging handler
     logger.addHandler(LoggingHandler(args.color, write=write))
     logger.setLevel(logging.INFO)
 
+    # Check if we have unresolved merge conflict files and fail fast.
+    if _has_unmerged_paths(runner):
+        logger.error('Unmerged files.  Resolve before committing.')
+        return 1
+
     if args.no_stash or args.all_files:
         ctx = noop_context()
     else:

{"golden_diff": "diff --git a/pre_commit/commands.py b/pre_commit/commands.py\n--- a/pre_commit/commands.py\n+++ b/pre_commit/commands.py\n@@ -229,11 +229,21 @@\n         return 1\n \n \n+def _has_unmerged_paths(runner):\n+    _, stdout, _ = runner.cmd_runner.run(['git', 'ls-files', '--unmerged'])\n+    return bool(stdout.strip())\n+\n+\n def run(runner, args, write=sys.stdout.write):\n     # Set up our logging handler\n     logger.addHandler(LoggingHandler(args.color, write=write))\n     logger.setLevel(logging.INFO)\n \n+    # Check if we have unresolved merge conflict files and fail fast.\n+    if _has_unmerged_paths(runner):\n+        logger.error('Unmerged files.  Resolve before committing.')\n+        return 1\n+\n     if args.no_stash or args.all_files:\n         ctx = noop_context()\n     else:\n", "issue": "pre-commit crashes when running during unresolved merge conflict\nI intentionally forced the following by making two branches conflict and then editing a file on that branch.  `pre-commit` should fail-fast in a merge conflict situation.\n\n```\n$ git diff --exit-code\ndiff --cc foo.txt\nindex 8ff26e7,c148433..0000000\n--- a/foo.txt\n+++ b/foo.txt\n@@@ -1,4 -1,5 +1,11 @@@\n  asdf\n++<<<<<<< HEAD\n +fdsa\n +yeah\n +yeah\n++=======\n+ asdf\n+ asdf\n+ asdf\n+ \n++>>>>>>> derp\ndiff --git a/git_code_debt/generate.py b/git_code_debt/generate.py\nindex 12ceec6..967506e 100644\n--- a/git_code_debt/generate.py\n+++ b/git_code_debt/generate.py\n@@ -12,6 +12,7 @@ from git_code_debt.logic import get_previous_sha\n from git_code_debt.logic import insert_metric_values\n from git_code_debt.repo_parser import RepoParser\n\n+\n def get_metrics(diff, metric_parsers):\n     def get_all_metrics(file_diff_stats):\n         for metric_parser_cls in metric_parsers:\n(py_env)[anthony@anthony-VirtualBox git-code-debt (herp|MERGING)]$ echo $?\n1\n(py_env)[anthony@anthony-VirtualBox git-code-debt (herp|MERGING)]$ pre-commit \n[WARNING] Unstaged files detected.\n[INFO] Stashing unstaged files to /tmp/git-code-debt/.pre-commit-files/patch1397455577.\nTraceback (most recent call last):\n  File \"/tmp/git-code-debt/py_env/bin/pre-commit\", line 9, in <module>\n    load_entry_point('pre-commit==0.0.0', 'console_scripts', 'pre-commit')()\n  File \"/tmp/git-code-debt/py_env/local/lib/python2.7/site-packages/pre_commit/util.py\", line 52, in wrapper\n    return func(argv)\n  File \"/tmp/git-code-debt/py_env/local/lib/python2.7/site-packages/pre_commit/run.py\", line 59, in run\n    return commands.run(runner, args)\n  File \"/tmp/git-code-debt/py_env/local/lib/python2.7/site-packages/pre_commit/commands.py\", line 242, in run\n    with ctx:\n  File \"/usr/lib/python2.7/contextlib.py\", line 17, in __enter__\n    return self.gen.next()\n  File \"/tmp/git-code-debt/py_env/local/lib/python2.7/site-packages/pre_commit/staged_files_only.py\", line 35, in staged_files_only\n    cmd_runner.run(['git', 'checkout', '--', '.'])\n  File \"/tmp/git-code-debt/py_env/local/lib/python2.7/site-packages/pre_commit/prefixed_command_runner.py\", line 77, in run\n    returncode, replaced_cmd, retcode, output=(stdout, stderr),\npre_commit.prefixed_command_runner.CalledProcessError: Command: ['git', 'checkout', '--', '.']\nReturn code: 1\nExpected return code: 0\nOutput: (u'', u\"error: path 'foo.txt' is unmerged\\n\")\n\n(py_env)[anthony@anthony-VirtualBox git-code-debt (herp|MERGING)]$ \n```\n\n", "before_files": [{"content": "from __future__ import print_function\n\nimport logging\nimport os\nimport pkg_resources\nimport shutil\nimport stat\nimport subprocess\nimport sys\nfrom asottile.ordereddict import OrderedDict\nfrom asottile.yaml import ordered_dump\nfrom asottile.yaml import ordered_load\nfrom plumbum import local\n\nimport pre_commit.constants as C\nfrom pre_commit import git\nfrom pre_commit import color\nfrom pre_commit.clientlib.validate_config import CONFIG_JSON_SCHEMA\nfrom pre_commit.clientlib.validate_config import load_config\nfrom pre_commit.jsonschema_extensions import remove_defaults\nfrom pre_commit.logging_handler import LoggingHandler\nfrom pre_commit.repository import Repository\nfrom pre_commit.staged_files_only import staged_files_only\nfrom pre_commit.util import noop_context\n\n\nlogger = logging.getLogger('pre_commit')\n\nCOLS = int(subprocess.Popen(['tput', 'cols'], stdout=subprocess.PIPE).communicate()[0])\n\nPASS_FAIL_LENGTH = 6\n\n\ndef install(runner):\n    \"\"\"Install the pre-commit hooks.\"\"\"\n    pre_commit_file = pkg_resources.resource_filename('pre_commit', 'resources/pre-commit.sh')\n    with open(runner.pre_commit_path, 'w') as pre_commit_file_obj:\n        pre_commit_file_obj.write(open(pre_commit_file).read())\n\n    original_mode = os.stat(runner.pre_commit_path).st_mode\n    os.chmod(\n        runner.pre_commit_path,\n        original_mode | stat.S_IXUSR | stat.S_IXGRP | stat.S_IXOTH,\n    )\n\n    print('pre-commit installed at {0}'.format(runner.pre_commit_path))\n\n    return 0\n\n\ndef uninstall(runner):\n    \"\"\"Uninstall the pre-commit hooks.\"\"\"\n    if os.path.exists(runner.pre_commit_path):\n        os.remove(runner.pre_commit_path)\n        print('pre-commit uninstalled')\n    return 0\n\n\nclass RepositoryCannotBeUpdatedError(RuntimeError):\n    pass\n\n\ndef _update_repository(repo_config):\n    \"\"\"Updates a repository to the tip of `master`.  If the repository cannot\n    be updated because a hook that is configured does not exist in `master`,\n    this raises a RepositoryCannotBeUpdatedError\n\n    Args:\n        repo_config - A config for a repository\n    \"\"\"\n    repo = Repository(repo_config)\n\n    with repo.in_checkout():\n        local['git']['fetch']()\n        head_sha = local['git']['rev-parse', 'origin/master']().strip()\n\n    # Don't bother trying to update if our sha is the same\n    if head_sha == repo_config['sha']:\n        return repo_config\n\n    # Construct a new config with the head sha\n    new_config = OrderedDict(repo_config)\n    new_config['sha'] = head_sha\n    new_repo = Repository(new_config)\n\n    # See if any of our hooks were deleted with the new commits\n    hooks = set(repo.hooks.keys())\n    hooks_missing = hooks - (hooks & set(new_repo.manifest.keys()))\n    if hooks_missing:\n        raise RepositoryCannotBeUpdatedError(\n            'Cannot update because the tip of master is missing these hooks:\\n'\n            '{0}'.format(', '.join(sorted(hooks_missing)))\n        )\n\n    return remove_defaults([new_config], CONFIG_JSON_SCHEMA)[0]\n\n\ndef autoupdate(runner):\n    \"\"\"Auto-update the pre-commit config to the latest versions of repos.\"\"\"\n    retv = 0\n    output_configs = []\n    changed = False\n\n    input_configs = load_config(\n        runner.config_file_path,\n        load_strategy=ordered_load,\n    )\n\n    for repo_config in input_configs:\n        print('Updating {0}...'.format(repo_config['repo']), end='')\n        try:\n            new_repo_config = _update_repository(repo_config)\n        except RepositoryCannotBeUpdatedError as error:\n            print(error.args[0])\n            output_configs.append(repo_config)\n            retv = 1\n            continue\n\n        if new_repo_config['sha'] != repo_config['sha']:\n            changed = True\n            print(\n                'updating {0} -> {1}.'.format(\n                    repo_config['sha'], new_repo_config['sha'],\n                )\n            )\n            output_configs.append(new_repo_config)\n        else:\n            print('already up to date.')\n            output_configs.append(repo_config)\n\n    if changed:\n        with open(runner.config_file_path, 'w') as config_file:\n            config_file.write(\n                ordered_dump(output_configs, **C.YAML_DUMP_KWARGS)\n            )\n\n    return retv\n\n\ndef clean(runner):\n    if os.path.exists(runner.hooks_workspace_path):\n        shutil.rmtree(runner.hooks_workspace_path)\n        print('Cleaned {0}.'.format(runner.hooks_workspace_path))\n    return 0\n\n\ndef _run_single_hook(runner, repository, hook_id, args, write):\n    if args.all_files:\n        get_filenames = git.get_all_files_matching\n    else:\n        get_filenames = git.get_staged_files_matching\n\n    hook = repository.hooks[hook_id]\n\n    filenames = get_filenames(hook['files'], hook['exclude'])\n    if not filenames:\n        no_files_msg = '(no files to check) '\n        skipped_msg = 'Skipped'\n        write(\n            '{0}{1}{2}{3}\\n'.format(\n                hook['name'],\n                '.' * (\n                    COLS -\n                    len(hook['name']) -\n                    len(no_files_msg) -\n                    len(skipped_msg) -\n                    6\n                ),\n                no_files_msg,\n                color.format_color(skipped_msg, color.TURQUOISE, args.color),\n            )\n        )\n        return 0\n\n    # Print the hook and the dots first in case the hook takes hella long to\n    # run.\n    write(\n        '{0}{1}'.format(\n            hook['name'],\n            '.' * (COLS - len(hook['name']) - PASS_FAIL_LENGTH - 6),\n        ),\n    )\n    sys.stdout.flush()\n\n    retcode, stdout, stderr = repository.run_hook(\n        runner.cmd_runner,\n        hook_id,\n        filenames,\n    )\n\n    if retcode != repository.hooks[hook_id]['expected_return_value']:\n        retcode = 1\n        print_color = color.RED\n        pass_fail = 'Failed'\n    else:\n        retcode = 0\n        print_color = color.GREEN\n        pass_fail = 'Passed'\n\n    write(color.format_color(pass_fail, print_color, args.color) + '\\n')\n\n    if (stdout or stderr) and (retcode or args.verbose):\n        write('\\n')\n        for output in (stdout, stderr):\n            if output.strip():\n                write(output.strip() + '\\n')\n        write('\\n')\n\n    return retcode\n\n\ndef _run_hooks(runner, args, write):\n    \"\"\"Actually run the hooks.\"\"\"\n    retval = 0\n\n    for repo in runner.repositories:\n        for hook_id in repo.hooks:\n            retval |= _run_single_hook(runner, repo, hook_id, args, write=write)\n\n    return retval\n\n\ndef _run_hook(runner, hook_id, args, write):\n    for repo in runner.repositories:\n        if hook_id in repo.hooks:\n            return _run_single_hook(runner, repo, hook_id, args, write=write)\n    else:\n        write('No hook with id `{0}`\\n'.format(hook_id))\n        return 1\n\n\ndef run(runner, args, write=sys.stdout.write):\n    # Set up our logging handler\n    logger.addHandler(LoggingHandler(args.color, write=write))\n    logger.setLevel(logging.INFO)\n\n    if args.no_stash or args.all_files:\n        ctx = noop_context()\n    else:\n        ctx = staged_files_only(runner.cmd_runner)\n\n    with ctx:\n        if args.hook:\n            return _run_hook(runner, args.hook, args, write=write)\n        else:\n            return _run_hooks(runner, args, write=write)\n", "path": "pre_commit/commands.py"}], "after_files": [{"content": "from __future__ import print_function\n\nimport logging\nimport os\nimport pkg_resources\nimport shutil\nimport stat\nimport subprocess\nimport sys\nfrom asottile.ordereddict import OrderedDict\nfrom asottile.yaml import ordered_dump\nfrom asottile.yaml import ordered_load\nfrom plumbum import local\n\nimport pre_commit.constants as C\nfrom pre_commit import git\nfrom pre_commit import color\nfrom pre_commit.clientlib.validate_config import CONFIG_JSON_SCHEMA\nfrom pre_commit.clientlib.validate_config import load_config\nfrom pre_commit.jsonschema_extensions import remove_defaults\nfrom pre_commit.logging_handler import LoggingHandler\nfrom pre_commit.repository import Repository\nfrom pre_commit.staged_files_only import staged_files_only\nfrom pre_commit.util import noop_context\n\n\nlogger = logging.getLogger('pre_commit')\n\nCOLS = int(subprocess.Popen(['tput', 'cols'], stdout=subprocess.PIPE).communicate()[0])\n\nPASS_FAIL_LENGTH = 6\n\n\ndef install(runner):\n    \"\"\"Install the pre-commit hooks.\"\"\"\n    pre_commit_file = pkg_resources.resource_filename('pre_commit', 'resources/pre-commit.sh')\n    with open(runner.pre_commit_path, 'w') as pre_commit_file_obj:\n        pre_commit_file_obj.write(open(pre_commit_file).read())\n\n    original_mode = os.stat(runner.pre_commit_path).st_mode\n    os.chmod(\n        runner.pre_commit_path,\n        original_mode | stat.S_IXUSR | stat.S_IXGRP | stat.S_IXOTH,\n    )\n\n    print('pre-commit installed at {0}'.format(runner.pre_commit_path))\n\n    return 0\n\n\ndef uninstall(runner):\n    \"\"\"Uninstall the pre-commit hooks.\"\"\"\n    if os.path.exists(runner.pre_commit_path):\n        os.remove(runner.pre_commit_path)\n        print('pre-commit uninstalled')\n    return 0\n\n\nclass RepositoryCannotBeUpdatedError(RuntimeError):\n    pass\n\n\ndef _update_repository(repo_config):\n    \"\"\"Updates a repository to the tip of `master`.  If the repository cannot\n    be updated because a hook that is configured does not exist in `master`,\n    this raises a RepositoryCannotBeUpdatedError\n\n    Args:\n        repo_config - A config for a repository\n    \"\"\"\n    repo = Repository(repo_config)\n\n    with repo.in_checkout():\n        local['git']['fetch']()\n        head_sha = local['git']['rev-parse', 'origin/master']().strip()\n\n    # Don't bother trying to update if our sha is the same\n    if head_sha == repo_config['sha']:\n        return repo_config\n\n    # Construct a new config with the head sha\n    new_config = OrderedDict(repo_config)\n    new_config['sha'] = head_sha\n    new_repo = Repository(new_config)\n\n    # See if any of our hooks were deleted with the new commits\n    hooks = set(repo.hooks.keys())\n    hooks_missing = hooks - (hooks & set(new_repo.manifest.keys()))\n    if hooks_missing:\n        raise RepositoryCannotBeUpdatedError(\n            'Cannot update because the tip of master is missing these hooks:\\n'\n            '{0}'.format(', '.join(sorted(hooks_missing)))\n        )\n\n    return remove_defaults([new_config], CONFIG_JSON_SCHEMA)[0]\n\n\ndef autoupdate(runner):\n    \"\"\"Auto-update the pre-commit config to the latest versions of repos.\"\"\"\n    retv = 0\n    output_configs = []\n    changed = False\n\n    input_configs = load_config(\n        runner.config_file_path,\n        load_strategy=ordered_load,\n    )\n\n    for repo_config in input_configs:\n        print('Updating {0}...'.format(repo_config['repo']), end='')\n        try:\n            new_repo_config = _update_repository(repo_config)\n        except RepositoryCannotBeUpdatedError as error:\n            print(error.args[0])\n            output_configs.append(repo_config)\n            retv = 1\n            continue\n\n        if new_repo_config['sha'] != repo_config['sha']:\n            changed = True\n            print(\n                'updating {0} -> {1}.'.format(\n                    repo_config['sha'], new_repo_config['sha'],\n                )\n            )\n            output_configs.append(new_repo_config)\n        else:\n            print('already up to date.')\n            output_configs.append(repo_config)\n\n    if changed:\n        with open(runner.config_file_path, 'w') as config_file:\n            config_file.write(\n                ordered_dump(output_configs, **C.YAML_DUMP_KWARGS)\n            )\n\n    return retv\n\n\ndef clean(runner):\n    if os.path.exists(runner.hooks_workspace_path):\n        shutil.rmtree(runner.hooks_workspace_path)\n        print('Cleaned {0}.'.format(runner.hooks_workspace_path))\n    return 0\n\n\ndef _run_single_hook(runner, repository, hook_id, args, write):\n    if args.all_files:\n        get_filenames = git.get_all_files_matching\n    else:\n        get_filenames = git.get_staged_files_matching\n\n    hook = repository.hooks[hook_id]\n\n    filenames = get_filenames(hook['files'], hook['exclude'])\n    if not filenames:\n        no_files_msg = '(no files to check) '\n        skipped_msg = 'Skipped'\n        write(\n            '{0}{1}{2}{3}\\n'.format(\n                hook['name'],\n                '.' * (\n                    COLS -\n                    len(hook['name']) -\n                    len(no_files_msg) -\n                    len(skipped_msg) -\n                    6\n                ),\n                no_files_msg,\n                color.format_color(skipped_msg, color.TURQUOISE, args.color),\n            )\n        )\n        return 0\n\n    # Print the hook and the dots first in case the hook takes hella long to\n    # run.\n    write(\n        '{0}{1}'.format(\n            hook['name'],\n            '.' * (COLS - len(hook['name']) - PASS_FAIL_LENGTH - 6),\n        ),\n    )\n    sys.stdout.flush()\n\n    retcode, stdout, stderr = repository.run_hook(\n        runner.cmd_runner,\n        hook_id,\n        filenames,\n    )\n\n    if retcode != repository.hooks[hook_id]['expected_return_value']:\n        retcode = 1\n        print_color = color.RED\n        pass_fail = 'Failed'\n    else:\n        retcode = 0\n        print_color = color.GREEN\n        pass_fail = 'Passed'\n\n    write(color.format_color(pass_fail, print_color, args.color) + '\\n')\n\n    if (stdout or stderr) and (retcode or args.verbose):\n        write('\\n')\n        for output in (stdout, stderr):\n            if output.strip():\n                write(output.strip() + '\\n')\n        write('\\n')\n\n    return retcode\n\n\ndef _run_hooks(runner, args, write):\n    \"\"\"Actually run the hooks.\"\"\"\n    retval = 0\n\n    for repo in runner.repositories:\n        for hook_id in repo.hooks:\n            retval |= _run_single_hook(runner, repo, hook_id, args, write=write)\n\n    return retval\n\n\ndef _run_hook(runner, hook_id, args, write):\n    for repo in runner.repositories:\n        if hook_id in repo.hooks:\n            return _run_single_hook(runner, repo, hook_id, args, write=write)\n    else:\n        write('No hook with id `{0}`\\n'.format(hook_id))\n        return 1\n\n\ndef _has_unmerged_paths(runner):\n    _, stdout, _ = runner.cmd_runner.run(['git', 'ls-files', '--unmerged'])\n    return bool(stdout.strip())\n\n\ndef run(runner, args, write=sys.stdout.write):\n    # Set up our logging handler\n    logger.addHandler(LoggingHandler(args.color, write=write))\n    logger.setLevel(logging.INFO)\n\n    # Check if we have unresolved merge conflict files and fail fast.\n    if _has_unmerged_paths(runner):\n        logger.error('Unmerged files.  Resolve before committing.')\n        return 1\n\n    if args.no_stash or args.all_files:\n        ctx = noop_context()\n    else:\n        ctx = staged_files_only(runner.cmd_runner)\n\n    with ctx:\n        if args.hook:\n            return _run_hook(runner, args.hook, args, write=write)\n        else:\n            return _run_hooks(runner, args, write=write)\n", "path": "pre_commit/commands.py"}]}