We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Hooks pre-fetching
Hi,

I want to suggest introducing a command for downloading all required hooks forcefully. The use case is simple:
1. I pack everything needed for testing into container
2. I deploy that into CI
3. It gets built and tests are ran

I'd like to separate fetching of the hooks and pre-installing them into a build step. This would allow me use caching for containers, saving time for tests.

P.S. Perhaps it's needed to add some argument to `run` command, so that it won't try downloading stuff when executing tests.

--- 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/install_uninstall.py`
Content:
```
1 from __future__ import print_function
2 from __future__ import unicode_literals
3 
4 import io
5 import os.path
6 import sys
7 
8 from pre_commit import output
9 from pre_commit.util import make_executable
10 from pre_commit.util import mkdirp
11 from pre_commit.util import resource_filename
12 
13 
14 # This is used to identify the hook file we install
15 PREVIOUS_IDENTIFYING_HASHES = (
16     '4d9958c90bc262f47553e2c073f14cfe',
17     'd8ee923c46731b42cd95cc869add4062',
18     '49fd668cb42069aa1b6048464be5d395',
19     '79f09a650522a87b0da915d0d983b2de',
20     'e358c9dae00eac5d06b38dfdb1e33a8c',
21 )
22 
23 
24 IDENTIFYING_HASH = '138fd403232d2ddd5efb44317e38bf03'
25 
26 
27 def is_our_pre_commit(filename):
28     if not os.path.exists(filename):
29         return False
30     return IDENTIFYING_HASH in io.open(filename).read()
31 
32 
33 def is_previous_pre_commit(filename):
34     if not os.path.exists(filename):
35         return False
36     contents = io.open(filename).read()
37     return any(hash in contents for hash in PREVIOUS_IDENTIFYING_HASHES)
38 
39 
40 def install(runner, overwrite=False, hooks=False, hook_type='pre-commit'):
41     """Install the pre-commit hooks."""
42     hook_path = runner.get_hook_path(hook_type)
43     legacy_path = hook_path + '.legacy'
44 
45     mkdirp(os.path.dirname(hook_path))
46 
47     # If we have an existing hook, move it to pre-commit.legacy
48     if (
49         os.path.lexists(hook_path) and
50         not is_our_pre_commit(hook_path) and
51         not is_previous_pre_commit(hook_path)
52     ):
53         os.rename(hook_path, legacy_path)
54 
55     # If we specify overwrite, we simply delete the legacy file
56     if overwrite and os.path.exists(legacy_path):
57         os.remove(legacy_path)
58     elif os.path.exists(legacy_path):
59         output.write_line(
60             'Running in migration mode with existing hooks at {}\n'
61             'Use -f to use only pre-commit.'.format(
62                 legacy_path,
63             )
64         )
65 
66     with io.open(hook_path, 'w') as pre_commit_file_obj:
67         if hook_type == 'pre-push':
68             with io.open(resource_filename('pre-push-tmpl')) as fp:
69                 pre_push_contents = fp.read()
70         else:
71             pre_push_contents = ''
72 
73         contents = io.open(resource_filename('hook-tmpl')).read().format(
74             sys_executable=sys.executable,
75             hook_type=hook_type,
76             pre_push=pre_push_contents,
77         )
78         pre_commit_file_obj.write(contents)
79     make_executable(hook_path)
80 
81     output.write_line('pre-commit installed at {}'.format(hook_path))
82 
83     # If they requested we install all of the hooks, do so.
84     if hooks:
85         for repository in runner.repositories:
86             repository.require_installed()
87 
88     return 0
89 
90 
91 def uninstall(runner, hook_type='pre-commit'):
92     """Uninstall the pre-commit hooks."""
93     hook_path = runner.get_hook_path(hook_type)
94     legacy_path = hook_path + '.legacy'
95     # If our file doesn't exist or it isn't ours, gtfo.
96     if (
97         not os.path.exists(hook_path) or (
98             not is_our_pre_commit(hook_path) and
99             not is_previous_pre_commit(hook_path)
100         )
101     ):
102         return 0
103 
104     os.remove(hook_path)
105     output.write_line('{} uninstalled'.format(hook_type))
106 
107     if os.path.exists(legacy_path):
108         os.rename(legacy_path, hook_path)
109         output.write_line('Restored previous hooks to {}'.format(hook_path))
110 
111     return 0
112
```

Path: `pre_commit/main.py`
Content:
```
1 from __future__ import unicode_literals
2 
3 import argparse
4 import os
5 import sys
6 
7 import pkg_resources
8 
9 from pre_commit import color
10 from pre_commit import five
11 from pre_commit import git
12 from pre_commit.commands.autoupdate import autoupdate
13 from pre_commit.commands.clean import clean
14 from pre_commit.commands.install_uninstall import install
15 from pre_commit.commands.install_uninstall import uninstall
16 from pre_commit.commands.run import run
17 from pre_commit.error_handler import error_handler
18 from pre_commit.logging_handler import add_logging_handler
19 from pre_commit.runner import Runner
20 
21 
22 # https://github.com/pre-commit/pre-commit/issues/217
23 # On OSX, making a virtualenv using pyvenv at . causes `virtualenv` and `pip`
24 # to install packages to the wrong place.  We don't want anything to deal with
25 # pyvenv
26 os.environ.pop('__PYVENV_LAUNCHER__', None)
27 
28 
29 def _add_color_option(parser):
30     parser.add_argument(
31         '--color', default='auto', type=color.use_color,
32         metavar='{' + ','.join(color.COLOR_CHOICES) + '}',
33         help='Whether to use color in output.  Defaults to `%(default)s`.',
34     )
35 
36 
37 def _add_config_option(parser):
38     parser.add_argument(
39         '-c', '--config', default='.pre-commit-config.yaml',
40         help='Path to alternate config file'
41     )
42 
43 
44 def main(argv=None):
45     argv = argv if argv is not None else sys.argv[1:]
46     argv = [five.to_text(arg) for arg in argv]
47     parser = argparse.ArgumentParser()
48 
49     # http://stackoverflow.com/a/8521644/812183
50     parser.add_argument(
51         '-V', '--version',
52         action='version',
53         version='%(prog)s {}'.format(
54             pkg_resources.get_distribution('pre-commit').version
55         )
56     )
57 
58     subparsers = parser.add_subparsers(dest='command')
59 
60     install_parser = subparsers.add_parser(
61         'install', help='Install the pre-commit script.',
62     )
63     _add_color_option(install_parser)
64     _add_config_option(install_parser)
65     install_parser.add_argument(
66         '-f', '--overwrite', action='store_true',
67         help='Overwrite existing hooks / remove migration mode.',
68     )
69     install_parser.add_argument(
70         '--install-hooks', action='store_true',
71         help=(
72             'Whether to install hook environments for all environments '
73             'in the config file.'
74         ),
75     )
76     install_parser.add_argument(
77         '-t', '--hook-type', choices=('pre-commit', 'pre-push'),
78         default='pre-commit',
79     )
80 
81     uninstall_parser = subparsers.add_parser(
82         'uninstall', help='Uninstall the pre-commit script.',
83     )
84     _add_color_option(uninstall_parser)
85     _add_config_option(uninstall_parser)
86     uninstall_parser.add_argument(
87         '-t', '--hook-type', choices=('pre-commit', 'pre-push'),
88         default='pre-commit',
89     )
90 
91     clean_parser = subparsers.add_parser(
92         'clean', help='Clean out pre-commit files.',
93     )
94     _add_color_option(clean_parser)
95     _add_config_option(clean_parser)
96     autoupdate_parser = subparsers.add_parser(
97         'autoupdate',
98         help="Auto-update pre-commit config to the latest repos' versions.",
99     )
100     _add_color_option(autoupdate_parser)
101     _add_config_option(autoupdate_parser)
102 
103     run_parser = subparsers.add_parser('run', help='Run hooks.')
104     _add_color_option(run_parser)
105     _add_config_option(run_parser)
106     run_parser.add_argument('hook', nargs='?', help='A single hook-id to run')
107     run_parser.add_argument(
108         '--no-stash', default=False, action='store_true',
109         help='Use this option to prevent auto stashing of unstaged files.',
110     )
111     run_parser.add_argument(
112         '--verbose', '-v', action='store_true', default=False,
113     )
114     run_parser.add_argument(
115         '--origin', '-o',
116         help="The origin branch's commit_id when using `git push`.",
117     )
118     run_parser.add_argument(
119         '--source', '-s',
120         help="The remote branch's commit_id when using `git push`.",
121     )
122     run_parser.add_argument(
123         '--allow-unstaged-config', default=False, action='store_true',
124         help=(
125             'Allow an unstaged config to be present.  Note that this will '
126             'be stashed before parsing unless --no-stash is specified.'
127         ),
128     )
129     run_parser.add_argument(
130         '--hook-stage', choices=('commit', 'push'), default='commit',
131         help='The stage during which the hook is fired e.g. commit or push.',
132     )
133     run_mutex_group = run_parser.add_mutually_exclusive_group(required=False)
134     run_mutex_group.add_argument(
135         '--all-files', '-a', action='store_true', default=False,
136         help='Run on all the files in the repo.  Implies --no-stash.',
137     )
138     run_mutex_group.add_argument(
139         '--files', nargs='*', default=[],
140         help='Specific filenames to run hooks on.',
141     )
142 
143     help = subparsers.add_parser(
144         'help', help='Show help for a specific command.',
145     )
146     help.add_argument('help_cmd', nargs='?', help='Command to show help for.')
147 
148     # Argparse doesn't really provide a way to use a `default` subparser
149     if len(argv) == 0:
150         argv = ['run']
151     args = parser.parse_args(argv)
152     if args.command == 'run':
153         args.files = [
154             os.path.relpath(os.path.abspath(filename), git.get_root())
155             for filename in args.files
156         ]
157 
158     if args.command == 'help':
159         if args.help_cmd:
160             parser.parse_args([args.help_cmd, '--help'])
161         else:
162             parser.parse_args(['--help'])
163 
164     with error_handler():
165         add_logging_handler(args.color)
166         runner = Runner.create(args.config)
167         git.check_for_cygwin_mismatch()
168 
169         if args.command == 'install':
170             return install(
171                 runner, overwrite=args.overwrite, hooks=args.install_hooks,
172                 hook_type=args.hook_type,
173             )
174         elif args.command == 'uninstall':
175             return uninstall(runner, hook_type=args.hook_type)
176         elif args.command == 'clean':
177             return clean(runner)
178         elif args.command == 'autoupdate':
179             return autoupdate(runner)
180         elif args.command == 'run':
181             return run(runner, args)
182         else:
183             raise NotImplementedError(
184                 'Command {} not implemented.'.format(args.command)
185             )
186 
187         raise AssertionError(
188             'Command {} failed to exit with a returncode'.format(args.command)
189         )
190 
191 
192 if __name__ == '__main__':
193     exit(main())
194
```
--- 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/install_uninstall.py b/pre_commit/commands/install_uninstall.py
--- a/pre_commit/commands/install_uninstall.py
+++ b/pre_commit/commands/install_uninstall.py
@@ -82,12 +82,16 @@
 
     # If they requested we install all of the hooks, do so.
     if hooks:
-        for repository in runner.repositories:
-            repository.require_installed()
+        install_hooks(runner)
 
     return 0
 
 
+def install_hooks(runner):
+    for repository in runner.repositories:
+        repository.require_installed()
+
+
 def uninstall(runner, hook_type='pre-commit'):
     """Uninstall the pre-commit hooks."""
     hook_path = runner.get_hook_path(hook_type)
diff --git a/pre_commit/main.py b/pre_commit/main.py
--- a/pre_commit/main.py
+++ b/pre_commit/main.py
@@ -12,6 +12,7 @@
 from pre_commit.commands.autoupdate import autoupdate
 from pre_commit.commands.clean import clean
 from pre_commit.commands.install_uninstall import install
+from pre_commit.commands.install_uninstall import install_hooks
 from pre_commit.commands.install_uninstall import uninstall
 from pre_commit.commands.run import run
 from pre_commit.error_handler import error_handler
@@ -78,6 +79,17 @@
         default='pre-commit',
     )
 
+    install_hooks_parser = subparsers.add_parser(
+        'install-hooks',
+        help=(
+            'Install hook environemnts for all environemnts in the config '
+            'file.  You may find `pre-commit install --install-hooks` more '
+            'useful.'
+        ),
+    )
+    _add_color_option(install_hooks_parser)
+    _add_config_option(install_hooks_parser)
+
     uninstall_parser = subparsers.add_parser(
         'uninstall', help='Uninstall the pre-commit script.',
     )
@@ -171,6 +183,8 @@
                 runner, overwrite=args.overwrite, hooks=args.install_hooks,
                 hook_type=args.hook_type,
             )
+        elif args.command == 'install-hooks':
+            return install_hooks(runner)
         elif args.command == 'uninstall':
             return uninstall(runner, hook_type=args.hook_type)
         elif args.command == 'clean':

{"golden_diff": "diff --git a/pre_commit/commands/install_uninstall.py b/pre_commit/commands/install_uninstall.py\n--- a/pre_commit/commands/install_uninstall.py\n+++ b/pre_commit/commands/install_uninstall.py\n@@ -82,12 +82,16 @@\n \n     # If they requested we install all of the hooks, do so.\n     if hooks:\n-        for repository in runner.repositories:\n-            repository.require_installed()\n+        install_hooks(runner)\n \n     return 0\n \n \n+def install_hooks(runner):\n+    for repository in runner.repositories:\n+        repository.require_installed()\n+\n+\n def uninstall(runner, hook_type='pre-commit'):\n     \"\"\"Uninstall the pre-commit hooks.\"\"\"\n     hook_path = runner.get_hook_path(hook_type)\ndiff --git a/pre_commit/main.py b/pre_commit/main.py\n--- a/pre_commit/main.py\n+++ b/pre_commit/main.py\n@@ -12,6 +12,7 @@\n from pre_commit.commands.autoupdate import autoupdate\n from pre_commit.commands.clean import clean\n from pre_commit.commands.install_uninstall import install\n+from pre_commit.commands.install_uninstall import install_hooks\n from pre_commit.commands.install_uninstall import uninstall\n from pre_commit.commands.run import run\n from pre_commit.error_handler import error_handler\n@@ -78,6 +79,17 @@\n         default='pre-commit',\n     )\n \n+    install_hooks_parser = subparsers.add_parser(\n+        'install-hooks',\n+        help=(\n+            'Install hook environemnts for all environemnts in the config '\n+            'file.  You may find `pre-commit install --install-hooks` more '\n+            'useful.'\n+        ),\n+    )\n+    _add_color_option(install_hooks_parser)\n+    _add_config_option(install_hooks_parser)\n+\n     uninstall_parser = subparsers.add_parser(\n         'uninstall', help='Uninstall the pre-commit script.',\n     )\n@@ -171,6 +183,8 @@\n                 runner, overwrite=args.overwrite, hooks=args.install_hooks,\n                 hook_type=args.hook_type,\n             )\n+        elif args.command == 'install-hooks':\n+            return install_hooks(runner)\n         elif args.command == 'uninstall':\n             return uninstall(runner, hook_type=args.hook_type)\n         elif args.command == 'clean':\n", "issue": "Hooks pre-fetching\nHi,\r\n\r\nI want to suggest introducing a command for downloading all required hooks forcefully. The use case is simple:\r\n1. I pack everything needed for testing into container\r\n2. I deploy that into CI\r\n3. It gets built and tests are ran\r\n\r\nI'd like to separate fetching of the hooks and pre-installing them into a build step. This would allow me use caching for containers, saving time for tests.\r\n\r\nP.S. Perhaps it's needed to add some argument to `run` command, so that it won't try downloading stuff when executing tests.\n", "before_files": [{"content": "from __future__ import print_function\nfrom __future__ import unicode_literals\n\nimport io\nimport os.path\nimport sys\n\nfrom pre_commit import output\nfrom pre_commit.util import make_executable\nfrom pre_commit.util import mkdirp\nfrom pre_commit.util import resource_filename\n\n\n# This is used to identify the hook file we install\nPREVIOUS_IDENTIFYING_HASHES = (\n    '4d9958c90bc262f47553e2c073f14cfe',\n    'd8ee923c46731b42cd95cc869add4062',\n    '49fd668cb42069aa1b6048464be5d395',\n    '79f09a650522a87b0da915d0d983b2de',\n    'e358c9dae00eac5d06b38dfdb1e33a8c',\n)\n\n\nIDENTIFYING_HASH = '138fd403232d2ddd5efb44317e38bf03'\n\n\ndef is_our_pre_commit(filename):\n    if not os.path.exists(filename):\n        return False\n    return IDENTIFYING_HASH in io.open(filename).read()\n\n\ndef is_previous_pre_commit(filename):\n    if not os.path.exists(filename):\n        return False\n    contents = io.open(filename).read()\n    return any(hash in contents for hash in PREVIOUS_IDENTIFYING_HASHES)\n\n\ndef install(runner, overwrite=False, hooks=False, hook_type='pre-commit'):\n    \"\"\"Install the pre-commit hooks.\"\"\"\n    hook_path = runner.get_hook_path(hook_type)\n    legacy_path = hook_path + '.legacy'\n\n    mkdirp(os.path.dirname(hook_path))\n\n    # If we have an existing hook, move it to pre-commit.legacy\n    if (\n        os.path.lexists(hook_path) and\n        not is_our_pre_commit(hook_path) and\n        not is_previous_pre_commit(hook_path)\n    ):\n        os.rename(hook_path, legacy_path)\n\n    # If we specify overwrite, we simply delete the legacy file\n    if overwrite and os.path.exists(legacy_path):\n        os.remove(legacy_path)\n    elif os.path.exists(legacy_path):\n        output.write_line(\n            'Running in migration mode with existing hooks at {}\\n'\n            'Use -f to use only pre-commit.'.format(\n                legacy_path,\n            )\n        )\n\n    with io.open(hook_path, 'w') as pre_commit_file_obj:\n        if hook_type == 'pre-push':\n            with io.open(resource_filename('pre-push-tmpl')) as fp:\n                pre_push_contents = fp.read()\n        else:\n            pre_push_contents = ''\n\n        contents = io.open(resource_filename('hook-tmpl')).read().format(\n            sys_executable=sys.executable,\n            hook_type=hook_type,\n            pre_push=pre_push_contents,\n        )\n        pre_commit_file_obj.write(contents)\n    make_executable(hook_path)\n\n    output.write_line('pre-commit installed at {}'.format(hook_path))\n\n    # If they requested we install all of the hooks, do so.\n    if hooks:\n        for repository in runner.repositories:\n            repository.require_installed()\n\n    return 0\n\n\ndef uninstall(runner, hook_type='pre-commit'):\n    \"\"\"Uninstall the pre-commit hooks.\"\"\"\n    hook_path = runner.get_hook_path(hook_type)\n    legacy_path = hook_path + '.legacy'\n    # If our file doesn't exist or it isn't ours, gtfo.\n    if (\n        not os.path.exists(hook_path) or (\n            not is_our_pre_commit(hook_path) and\n            not is_previous_pre_commit(hook_path)\n        )\n    ):\n        return 0\n\n    os.remove(hook_path)\n    output.write_line('{} uninstalled'.format(hook_type))\n\n    if os.path.exists(legacy_path):\n        os.rename(legacy_path, hook_path)\n        output.write_line('Restored previous hooks to {}'.format(hook_path))\n\n    return 0\n", "path": "pre_commit/commands/install_uninstall.py"}, {"content": "from __future__ import unicode_literals\n\nimport argparse\nimport os\nimport sys\n\nimport pkg_resources\n\nfrom pre_commit import color\nfrom pre_commit import five\nfrom pre_commit import git\nfrom pre_commit.commands.autoupdate import autoupdate\nfrom pre_commit.commands.clean import clean\nfrom pre_commit.commands.install_uninstall import install\nfrom pre_commit.commands.install_uninstall import uninstall\nfrom pre_commit.commands.run import run\nfrom pre_commit.error_handler import error_handler\nfrom pre_commit.logging_handler import add_logging_handler\nfrom pre_commit.runner import Runner\n\n\n# https://github.com/pre-commit/pre-commit/issues/217\n# On OSX, making a virtualenv using pyvenv at . causes `virtualenv` and `pip`\n# to install packages to the wrong place.  We don't want anything to deal with\n# pyvenv\nos.environ.pop('__PYVENV_LAUNCHER__', None)\n\n\ndef _add_color_option(parser):\n    parser.add_argument(\n        '--color', default='auto', type=color.use_color,\n        metavar='{' + ','.join(color.COLOR_CHOICES) + '}',\n        help='Whether to use color in output.  Defaults to `%(default)s`.',\n    )\n\n\ndef _add_config_option(parser):\n    parser.add_argument(\n        '-c', '--config', default='.pre-commit-config.yaml',\n        help='Path to alternate config file'\n    )\n\n\ndef main(argv=None):\n    argv = argv if argv is not None else sys.argv[1:]\n    argv = [five.to_text(arg) for arg in argv]\n    parser = argparse.ArgumentParser()\n\n    # http://stackoverflow.com/a/8521644/812183\n    parser.add_argument(\n        '-V', '--version',\n        action='version',\n        version='%(prog)s {}'.format(\n            pkg_resources.get_distribution('pre-commit').version\n        )\n    )\n\n    subparsers = parser.add_subparsers(dest='command')\n\n    install_parser = subparsers.add_parser(\n        'install', help='Install the pre-commit script.',\n    )\n    _add_color_option(install_parser)\n    _add_config_option(install_parser)\n    install_parser.add_argument(\n        '-f', '--overwrite', action='store_true',\n        help='Overwrite existing hooks / remove migration mode.',\n    )\n    install_parser.add_argument(\n        '--install-hooks', action='store_true',\n        help=(\n            'Whether to install hook environments for all environments '\n            'in the config file.'\n        ),\n    )\n    install_parser.add_argument(\n        '-t', '--hook-type', choices=('pre-commit', 'pre-push'),\n        default='pre-commit',\n    )\n\n    uninstall_parser = subparsers.add_parser(\n        'uninstall', help='Uninstall the pre-commit script.',\n    )\n    _add_color_option(uninstall_parser)\n    _add_config_option(uninstall_parser)\n    uninstall_parser.add_argument(\n        '-t', '--hook-type', choices=('pre-commit', 'pre-push'),\n        default='pre-commit',\n    )\n\n    clean_parser = subparsers.add_parser(\n        'clean', help='Clean out pre-commit files.',\n    )\n    _add_color_option(clean_parser)\n    _add_config_option(clean_parser)\n    autoupdate_parser = subparsers.add_parser(\n        'autoupdate',\n        help=\"Auto-update pre-commit config to the latest repos' versions.\",\n    )\n    _add_color_option(autoupdate_parser)\n    _add_config_option(autoupdate_parser)\n\n    run_parser = subparsers.add_parser('run', help='Run hooks.')\n    _add_color_option(run_parser)\n    _add_config_option(run_parser)\n    run_parser.add_argument('hook', nargs='?', help='A single hook-id to run')\n    run_parser.add_argument(\n        '--no-stash', default=False, action='store_true',\n        help='Use this option to prevent auto stashing of unstaged files.',\n    )\n    run_parser.add_argument(\n        '--verbose', '-v', action='store_true', default=False,\n    )\n    run_parser.add_argument(\n        '--origin', '-o',\n        help=\"The origin branch's commit_id when using `git push`.\",\n    )\n    run_parser.add_argument(\n        '--source', '-s',\n        help=\"The remote branch's commit_id when using `git push`.\",\n    )\n    run_parser.add_argument(\n        '--allow-unstaged-config', default=False, action='store_true',\n        help=(\n            'Allow an unstaged config to be present.  Note that this will '\n            'be stashed before parsing unless --no-stash is specified.'\n        ),\n    )\n    run_parser.add_argument(\n        '--hook-stage', choices=('commit', 'push'), default='commit',\n        help='The stage during which the hook is fired e.g. commit or push.',\n    )\n    run_mutex_group = run_parser.add_mutually_exclusive_group(required=False)\n    run_mutex_group.add_argument(\n        '--all-files', '-a', action='store_true', default=False,\n        help='Run on all the files in the repo.  Implies --no-stash.',\n    )\n    run_mutex_group.add_argument(\n        '--files', nargs='*', default=[],\n        help='Specific filenames to run hooks on.',\n    )\n\n    help = subparsers.add_parser(\n        'help', help='Show help for a specific command.',\n    )\n    help.add_argument('help_cmd', nargs='?', help='Command to show help for.')\n\n    # Argparse doesn't really provide a way to use a `default` subparser\n    if len(argv) == 0:\n        argv = ['run']\n    args = parser.parse_args(argv)\n    if args.command == 'run':\n        args.files = [\n            os.path.relpath(os.path.abspath(filename), git.get_root())\n            for filename in args.files\n        ]\n\n    if args.command == 'help':\n        if args.help_cmd:\n            parser.parse_args([args.help_cmd, '--help'])\n        else:\n            parser.parse_args(['--help'])\n\n    with error_handler():\n        add_logging_handler(args.color)\n        runner = Runner.create(args.config)\n        git.check_for_cygwin_mismatch()\n\n        if args.command == 'install':\n            return install(\n                runner, overwrite=args.overwrite, hooks=args.install_hooks,\n                hook_type=args.hook_type,\n            )\n        elif args.command == 'uninstall':\n            return uninstall(runner, hook_type=args.hook_type)\n        elif args.command == 'clean':\n            return clean(runner)\n        elif args.command == 'autoupdate':\n            return autoupdate(runner)\n        elif args.command == 'run':\n            return run(runner, args)\n        else:\n            raise NotImplementedError(\n                'Command {} not implemented.'.format(args.command)\n            )\n\n        raise AssertionError(\n            'Command {} failed to exit with a returncode'.format(args.command)\n        )\n\n\nif __name__ == '__main__':\n    exit(main())\n", "path": "pre_commit/main.py"}], "after_files": [{"content": "from __future__ import print_function\nfrom __future__ import unicode_literals\n\nimport io\nimport os.path\nimport sys\n\nfrom pre_commit import output\nfrom pre_commit.util import make_executable\nfrom pre_commit.util import mkdirp\nfrom pre_commit.util import resource_filename\n\n\n# This is used to identify the hook file we install\nPREVIOUS_IDENTIFYING_HASHES = (\n    '4d9958c90bc262f47553e2c073f14cfe',\n    'd8ee923c46731b42cd95cc869add4062',\n    '49fd668cb42069aa1b6048464be5d395',\n    '79f09a650522a87b0da915d0d983b2de',\n    'e358c9dae00eac5d06b38dfdb1e33a8c',\n)\n\n\nIDENTIFYING_HASH = '138fd403232d2ddd5efb44317e38bf03'\n\n\ndef is_our_pre_commit(filename):\n    if not os.path.exists(filename):\n        return False\n    return IDENTIFYING_HASH in io.open(filename).read()\n\n\ndef is_previous_pre_commit(filename):\n    if not os.path.exists(filename):\n        return False\n    contents = io.open(filename).read()\n    return any(hash in contents for hash in PREVIOUS_IDENTIFYING_HASHES)\n\n\ndef install(runner, overwrite=False, hooks=False, hook_type='pre-commit'):\n    \"\"\"Install the pre-commit hooks.\"\"\"\n    hook_path = runner.get_hook_path(hook_type)\n    legacy_path = hook_path + '.legacy'\n\n    mkdirp(os.path.dirname(hook_path))\n\n    # If we have an existing hook, move it to pre-commit.legacy\n    if (\n        os.path.lexists(hook_path) and\n        not is_our_pre_commit(hook_path) and\n        not is_previous_pre_commit(hook_path)\n    ):\n        os.rename(hook_path, legacy_path)\n\n    # If we specify overwrite, we simply delete the legacy file\n    if overwrite and os.path.exists(legacy_path):\n        os.remove(legacy_path)\n    elif os.path.exists(legacy_path):\n        output.write_line(\n            'Running in migration mode with existing hooks at {}\\n'\n            'Use -f to use only pre-commit.'.format(\n                legacy_path,\n            )\n        )\n\n    with io.open(hook_path, 'w') as pre_commit_file_obj:\n        if hook_type == 'pre-push':\n            with io.open(resource_filename('pre-push-tmpl')) as fp:\n                pre_push_contents = fp.read()\n        else:\n            pre_push_contents = ''\n\n        contents = io.open(resource_filename('hook-tmpl')).read().format(\n            sys_executable=sys.executable,\n            hook_type=hook_type,\n            pre_push=pre_push_contents,\n        )\n        pre_commit_file_obj.write(contents)\n    make_executable(hook_path)\n\n    output.write_line('pre-commit installed at {}'.format(hook_path))\n\n    # If they requested we install all of the hooks, do so.\n    if hooks:\n        install_hooks(runner)\n\n    return 0\n\n\ndef install_hooks(runner):\n    for repository in runner.repositories:\n        repository.require_installed()\n\n\ndef uninstall(runner, hook_type='pre-commit'):\n    \"\"\"Uninstall the pre-commit hooks.\"\"\"\n    hook_path = runner.get_hook_path(hook_type)\n    legacy_path = hook_path + '.legacy'\n    # If our file doesn't exist or it isn't ours, gtfo.\n    if (\n        not os.path.exists(hook_path) or (\n            not is_our_pre_commit(hook_path) and\n            not is_previous_pre_commit(hook_path)\n        )\n    ):\n        return 0\n\n    os.remove(hook_path)\n    output.write_line('{} uninstalled'.format(hook_type))\n\n    if os.path.exists(legacy_path):\n        os.rename(legacy_path, hook_path)\n        output.write_line('Restored previous hooks to {}'.format(hook_path))\n\n    return 0\n", "path": "pre_commit/commands/install_uninstall.py"}, {"content": "from __future__ import unicode_literals\n\nimport argparse\nimport os\nimport sys\n\nimport pkg_resources\n\nfrom pre_commit import color\nfrom pre_commit import five\nfrom pre_commit import git\nfrom pre_commit.commands.autoupdate import autoupdate\nfrom pre_commit.commands.clean import clean\nfrom pre_commit.commands.install_uninstall import install\nfrom pre_commit.commands.install_uninstall import install_hooks\nfrom pre_commit.commands.install_uninstall import uninstall\nfrom pre_commit.commands.run import run\nfrom pre_commit.error_handler import error_handler\nfrom pre_commit.logging_handler import add_logging_handler\nfrom pre_commit.runner import Runner\n\n\n# https://github.com/pre-commit/pre-commit/issues/217\n# On OSX, making a virtualenv using pyvenv at . causes `virtualenv` and `pip`\n# to install packages to the wrong place.  We don't want anything to deal with\n# pyvenv\nos.environ.pop('__PYVENV_LAUNCHER__', None)\n\n\ndef _add_color_option(parser):\n    parser.add_argument(\n        '--color', default='auto', type=color.use_color,\n        metavar='{' + ','.join(color.COLOR_CHOICES) + '}',\n        help='Whether to use color in output.  Defaults to `%(default)s`.',\n    )\n\n\ndef _add_config_option(parser):\n    parser.add_argument(\n        '-c', '--config', default='.pre-commit-config.yaml',\n        help='Path to alternate config file'\n    )\n\n\ndef main(argv=None):\n    argv = argv if argv is not None else sys.argv[1:]\n    argv = [five.to_text(arg) for arg in argv]\n    parser = argparse.ArgumentParser()\n\n    # http://stackoverflow.com/a/8521644/812183\n    parser.add_argument(\n        '-V', '--version',\n        action='version',\n        version='%(prog)s {}'.format(\n            pkg_resources.get_distribution('pre-commit').version\n        )\n    )\n\n    subparsers = parser.add_subparsers(dest='command')\n\n    install_parser = subparsers.add_parser(\n        'install', help='Install the pre-commit script.',\n    )\n    _add_color_option(install_parser)\n    _add_config_option(install_parser)\n    install_parser.add_argument(\n        '-f', '--overwrite', action='store_true',\n        help='Overwrite existing hooks / remove migration mode.',\n    )\n    install_parser.add_argument(\n        '--install-hooks', action='store_true',\n        help=(\n            'Whether to install hook environments for all environments '\n            'in the config file.'\n        ),\n    )\n    install_parser.add_argument(\n        '-t', '--hook-type', choices=('pre-commit', 'pre-push'),\n        default='pre-commit',\n    )\n\n    install_hooks_parser = subparsers.add_parser(\n        'install-hooks',\n        help=(\n            'Install hook environemnts for all environemnts in the config '\n            'file.  You may find `pre-commit install --install-hooks` more '\n            'useful.'\n        ),\n    )\n    _add_color_option(install_hooks_parser)\n    _add_config_option(install_hooks_parser)\n\n    uninstall_parser = subparsers.add_parser(\n        'uninstall', help='Uninstall the pre-commit script.',\n    )\n    _add_color_option(uninstall_parser)\n    _add_config_option(uninstall_parser)\n    uninstall_parser.add_argument(\n        '-t', '--hook-type', choices=('pre-commit', 'pre-push'),\n        default='pre-commit',\n    )\n\n    clean_parser = subparsers.add_parser(\n        'clean', help='Clean out pre-commit files.',\n    )\n    _add_color_option(clean_parser)\n    _add_config_option(clean_parser)\n    autoupdate_parser = subparsers.add_parser(\n        'autoupdate',\n        help=\"Auto-update pre-commit config to the latest repos' versions.\",\n    )\n    _add_color_option(autoupdate_parser)\n    _add_config_option(autoupdate_parser)\n\n    run_parser = subparsers.add_parser('run', help='Run hooks.')\n    _add_color_option(run_parser)\n    _add_config_option(run_parser)\n    run_parser.add_argument('hook', nargs='?', help='A single hook-id to run')\n    run_parser.add_argument(\n        '--no-stash', default=False, action='store_true',\n        help='Use this option to prevent auto stashing of unstaged files.',\n    )\n    run_parser.add_argument(\n        '--verbose', '-v', action='store_true', default=False,\n    )\n    run_parser.add_argument(\n        '--origin', '-o',\n        help=\"The origin branch's commit_id when using `git push`.\",\n    )\n    run_parser.add_argument(\n        '--source', '-s',\n        help=\"The remote branch's commit_id when using `git push`.\",\n    )\n    run_parser.add_argument(\n        '--allow-unstaged-config', default=False, action='store_true',\n        help=(\n            'Allow an unstaged config to be present.  Note that this will '\n            'be stashed before parsing unless --no-stash is specified.'\n        ),\n    )\n    run_parser.add_argument(\n        '--hook-stage', choices=('commit', 'push'), default='commit',\n        help='The stage during which the hook is fired e.g. commit or push.',\n    )\n    run_mutex_group = run_parser.add_mutually_exclusive_group(required=False)\n    run_mutex_group.add_argument(\n        '--all-files', '-a', action='store_true', default=False,\n        help='Run on all the files in the repo.  Implies --no-stash.',\n    )\n    run_mutex_group.add_argument(\n        '--files', nargs='*', default=[],\n        help='Specific filenames to run hooks on.',\n    )\n\n    help = subparsers.add_parser(\n        'help', help='Show help for a specific command.',\n    )\n    help.add_argument('help_cmd', nargs='?', help='Command to show help for.')\n\n    # Argparse doesn't really provide a way to use a `default` subparser\n    if len(argv) == 0:\n        argv = ['run']\n    args = parser.parse_args(argv)\n    if args.command == 'run':\n        args.files = [\n            os.path.relpath(os.path.abspath(filename), git.get_root())\n            for filename in args.files\n        ]\n\n    if args.command == 'help':\n        if args.help_cmd:\n            parser.parse_args([args.help_cmd, '--help'])\n        else:\n            parser.parse_args(['--help'])\n\n    with error_handler():\n        add_logging_handler(args.color)\n        runner = Runner.create(args.config)\n        git.check_for_cygwin_mismatch()\n\n        if args.command == 'install':\n            return install(\n                runner, overwrite=args.overwrite, hooks=args.install_hooks,\n                hook_type=args.hook_type,\n            )\n        elif args.command == 'install-hooks':\n            return install_hooks(runner)\n        elif args.command == 'uninstall':\n            return uninstall(runner, hook_type=args.hook_type)\n        elif args.command == 'clean':\n            return clean(runner)\n        elif args.command == 'autoupdate':\n            return autoupdate(runner)\n        elif args.command == 'run':\n            return run(runner, args)\n        else:\n            raise NotImplementedError(\n                'Command {} not implemented.'.format(args.command)\n            )\n\n        raise AssertionError(\n            'Command {} failed to exit with a returncode'.format(args.command)\n        )\n\n\nif __name__ == '__main__':\n    exit(main())\n", "path": "pre_commit/main.py"}]}