We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Add warning for `files` / `exclude` containing `/*`
it's a common mistake to believe that those fields are globs, they're not -- they're regular expressions. (and matching `/*` is nonsense, it matches `''`, `'/'` as well as `'//////////////////////////////////////////////////////'`

--- 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/clientlib.py`
Content:
```
1 import argparse
2 import functools
3 import logging
4 import shlex
5 import sys
6 from typing import Any
7 from typing import Dict
8 from typing import Optional
9 from typing import Sequence
10 
11 import cfgv
12 from identify.identify import ALL_TAGS
13 
14 import pre_commit.constants as C
15 from pre_commit.color import add_color_option
16 from pre_commit.errors import FatalError
17 from pre_commit.languages.all import all_languages
18 from pre_commit.logging_handler import logging_handler
19 from pre_commit.util import parse_version
20 from pre_commit.util import yaml_load
21 
22 logger = logging.getLogger('pre_commit')
23 
24 check_string_regex = cfgv.check_and(cfgv.check_string, cfgv.check_regex)
25 
26 
27 def check_type_tag(tag: str) -> None:
28     if tag not in ALL_TAGS:
29         raise cfgv.ValidationError(
30             f'Type tag {tag!r} is not recognized.  '
31             f'Try upgrading identify and pre-commit?',
32         )
33 
34 
35 def check_min_version(version: str) -> None:
36     if parse_version(version) > parse_version(C.VERSION):
37         raise cfgv.ValidationError(
38             f'pre-commit version {version} is required but version '
39             f'{C.VERSION} is installed.  '
40             f'Perhaps run `pip install --upgrade pre-commit`.',
41         )
42 
43 
44 def _make_argparser(filenames_help: str) -> argparse.ArgumentParser:
45     parser = argparse.ArgumentParser()
46     parser.add_argument('filenames', nargs='*', help=filenames_help)
47     parser.add_argument('-V', '--version', action='version', version=C.VERSION)
48     add_color_option(parser)
49     return parser
50 
51 
52 MANIFEST_HOOK_DICT = cfgv.Map(
53     'Hook', 'id',
54 
55     cfgv.Required('id', cfgv.check_string),
56     cfgv.Required('name', cfgv.check_string),
57     cfgv.Required('entry', cfgv.check_string),
58     cfgv.Required('language', cfgv.check_one_of(all_languages)),
59     cfgv.Optional('alias', cfgv.check_string, ''),
60 
61     cfgv.Optional('files', check_string_regex, ''),
62     cfgv.Optional('exclude', check_string_regex, '^$'),
63     cfgv.Optional('types', cfgv.check_array(check_type_tag), ['file']),
64     cfgv.Optional('types_or', cfgv.check_array(check_type_tag), ['file']),
65     cfgv.Optional('exclude_types', cfgv.check_array(check_type_tag), []),
66 
67     cfgv.Optional(
68         'additional_dependencies', cfgv.check_array(cfgv.check_string), [],
69     ),
70     cfgv.Optional('args', cfgv.check_array(cfgv.check_string), []),
71     cfgv.Optional('always_run', cfgv.check_bool, False),
72     cfgv.Optional('pass_filenames', cfgv.check_bool, True),
73     cfgv.Optional('description', cfgv.check_string, ''),
74     cfgv.Optional('language_version', cfgv.check_string, C.DEFAULT),
75     cfgv.Optional('log_file', cfgv.check_string, ''),
76     cfgv.Optional('minimum_pre_commit_version', cfgv.check_string, '0'),
77     cfgv.Optional('require_serial', cfgv.check_bool, False),
78     cfgv.Optional('stages', cfgv.check_array(cfgv.check_one_of(C.STAGES)), []),
79     cfgv.Optional('verbose', cfgv.check_bool, False),
80 )
81 MANIFEST_SCHEMA = cfgv.Array(MANIFEST_HOOK_DICT)
82 
83 
84 class InvalidManifestError(FatalError):
85     pass
86 
87 
88 load_manifest = functools.partial(
89     cfgv.load_from_filename,
90     schema=MANIFEST_SCHEMA,
91     load_strategy=yaml_load,
92     exc_tp=InvalidManifestError,
93 )
94 
95 
96 def validate_manifest_main(argv: Optional[Sequence[str]] = None) -> int:
97     parser = _make_argparser('Manifest filenames.')
98     args = parser.parse_args(argv)
99 
100     with logging_handler(args.color):
101         ret = 0
102         for filename in args.filenames:
103             try:
104                 load_manifest(filename)
105             except InvalidManifestError as e:
106                 print(e)
107                 ret = 1
108         return ret
109 
110 
111 LOCAL = 'local'
112 META = 'meta'
113 
114 
115 class MigrateShaToRev:
116     key = 'rev'
117 
118     @staticmethod
119     def _cond(key: str) -> cfgv.Conditional:
120         return cfgv.Conditional(
121             key, cfgv.check_string,
122             condition_key='repo',
123             condition_value=cfgv.NotIn(LOCAL, META),
124             ensure_absent=True,
125         )
126 
127     def check(self, dct: Dict[str, Any]) -> None:
128         if dct.get('repo') in {LOCAL, META}:
129             self._cond('rev').check(dct)
130             self._cond('sha').check(dct)
131         elif 'sha' in dct and 'rev' in dct:
132             raise cfgv.ValidationError('Cannot specify both sha and rev')
133         elif 'sha' in dct:
134             self._cond('sha').check(dct)
135         else:
136             self._cond('rev').check(dct)
137 
138     def apply_default(self, dct: Dict[str, Any]) -> None:
139         if 'sha' in dct:
140             dct['rev'] = dct.pop('sha')
141 
142     remove_default = cfgv.Required.remove_default
143 
144 
145 def _entry(modname: str) -> str:
146     """the hook `entry` is passed through `shlex.split()` by the command
147     runner, so to prevent issues with spaces and backslashes (on Windows)
148     it must be quoted here.
149     """
150     return f'{shlex.quote(sys.executable)} -m pre_commit.meta_hooks.{modname}'
151 
152 
153 def warn_unknown_keys_root(
154         extra: Sequence[str],
155         orig_keys: Sequence[str],
156         dct: Dict[str, str],
157 ) -> None:
158     logger.warning(f'Unexpected key(s) present at root: {", ".join(extra)}')
159 
160 
161 def warn_unknown_keys_repo(
162         extra: Sequence[str],
163         orig_keys: Sequence[str],
164         dct: Dict[str, str],
165 ) -> None:
166     logger.warning(
167         f'Unexpected key(s) present on {dct["repo"]}: {", ".join(extra)}',
168     )
169 
170 
171 _meta = (
172     (
173         'check-hooks-apply', (
174             ('name', 'Check hooks apply to the repository'),
175             ('files', C.CONFIG_FILE),
176             ('entry', _entry('check_hooks_apply')),
177         ),
178     ),
179     (
180         'check-useless-excludes', (
181             ('name', 'Check for useless excludes'),
182             ('files', C.CONFIG_FILE),
183             ('entry', _entry('check_useless_excludes')),
184         ),
185     ),
186     (
187         'identity', (
188             ('name', 'identity'),
189             ('verbose', True),
190             ('entry', _entry('identity')),
191         ),
192     ),
193 )
194 
195 META_HOOK_DICT = cfgv.Map(
196     'Hook', 'id',
197     cfgv.Required('id', cfgv.check_string),
198     cfgv.Required('id', cfgv.check_one_of(tuple(k for k, _ in _meta))),
199     # language must be system
200     cfgv.Optional('language', cfgv.check_one_of({'system'}), 'system'),
201     *(
202         # default to the hook definition for the meta hooks
203         cfgv.ConditionalOptional(key, cfgv.check_any, value, 'id', hook_id)
204         for hook_id, values in _meta
205         for key, value in values
206     ),
207     *(
208         # default to the "manifest" parsing
209         cfgv.OptionalNoDefault(item.key, item.check_fn)
210         # these will always be defaulted above
211         if item.key in {'name', 'language', 'entry'} else
212         item
213         for item in MANIFEST_HOOK_DICT.items
214     ),
215 )
216 CONFIG_HOOK_DICT = cfgv.Map(
217     'Hook', 'id',
218 
219     cfgv.Required('id', cfgv.check_string),
220 
221     # All keys in manifest hook dict are valid in a config hook dict, but
222     # are optional.
223     # No defaults are provided here as the config is merged on top of the
224     # manifest.
225     *(
226         cfgv.OptionalNoDefault(item.key, item.check_fn)
227         for item in MANIFEST_HOOK_DICT.items
228         if item.key != 'id'
229     ),
230 )
231 CONFIG_REPO_DICT = cfgv.Map(
232     'Repository', 'repo',
233 
234     cfgv.Required('repo', cfgv.check_string),
235 
236     cfgv.ConditionalRecurse(
237         'hooks', cfgv.Array(CONFIG_HOOK_DICT),
238         'repo', cfgv.NotIn(LOCAL, META),
239     ),
240     cfgv.ConditionalRecurse(
241         'hooks', cfgv.Array(MANIFEST_HOOK_DICT),
242         'repo', LOCAL,
243     ),
244     cfgv.ConditionalRecurse(
245         'hooks', cfgv.Array(META_HOOK_DICT),
246         'repo', META,
247     ),
248 
249     MigrateShaToRev(),
250     cfgv.WarnAdditionalKeys(('repo', 'rev', 'hooks'), warn_unknown_keys_repo),
251 )
252 DEFAULT_LANGUAGE_VERSION = cfgv.Map(
253     'DefaultLanguageVersion', None,
254     cfgv.NoAdditionalKeys(all_languages),
255     *(cfgv.Optional(x, cfgv.check_string, C.DEFAULT) for x in all_languages),
256 )
257 CONFIG_SCHEMA = cfgv.Map(
258     'Config', None,
259 
260     cfgv.RequiredRecurse('repos', cfgv.Array(CONFIG_REPO_DICT)),
261     cfgv.OptionalRecurse(
262         'default_language_version', DEFAULT_LANGUAGE_VERSION, {},
263     ),
264     cfgv.Optional(
265         'default_stages',
266         cfgv.check_array(cfgv.check_one_of(C.STAGES)),
267         C.STAGES,
268     ),
269     cfgv.Optional('files', check_string_regex, ''),
270     cfgv.Optional('exclude', check_string_regex, '^$'),
271     cfgv.Optional('fail_fast', cfgv.check_bool, False),
272     cfgv.Optional(
273         'minimum_pre_commit_version',
274         cfgv.check_and(cfgv.check_string, check_min_version),
275         '0',
276     ),
277     cfgv.WarnAdditionalKeys(
278         (
279             'repos',
280             'default_language_version',
281             'default_stages',
282             'files',
283             'exclude',
284             'fail_fast',
285             'minimum_pre_commit_version',
286         ),
287         warn_unknown_keys_root,
288     ),
289 )
290 
291 
292 class InvalidConfigError(FatalError):
293     pass
294 
295 
296 def ordered_load_normalize_legacy_config(contents: str) -> Dict[str, Any]:
297     data = yaml_load(contents)
298     if isinstance(data, list):
299         logger.warning(
300             'normalizing pre-commit configuration to a top-level map.  '
301             'support for top level list will be removed in a future version.  '
302             'run: `pre-commit migrate-config` to automatically fix this.',
303         )
304         return {'repos': data}
305     else:
306         return data
307 
308 
309 load_config = functools.partial(
310     cfgv.load_from_filename,
311     schema=CONFIG_SCHEMA,
312     load_strategy=ordered_load_normalize_legacy_config,
313     exc_tp=InvalidConfigError,
314 )
315 
316 
317 def validate_config_main(argv: Optional[Sequence[str]] = None) -> int:
318     parser = _make_argparser('Config filenames.')
319     args = parser.parse_args(argv)
320 
321     with logging_handler(args.color):
322         ret = 0
323         for filename in args.filenames:
324             try:
325                 load_config(filename)
326             except InvalidConfigError as e:
327                 print(e)
328                 ret = 1
329         return ret
330
```
--- 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/clientlib.py b/pre_commit/clientlib.py
--- a/pre_commit/clientlib.py
+++ b/pre_commit/clientlib.py
@@ -112,6 +112,18 @@
 META = 'meta'
 
 
+class OptionalSensibleRegex(cfgv.OptionalNoDefault):
+    def check(self, dct: Dict[str, Any]) -> None:
+        super().check(dct)
+
+        if '/*' in dct.get(self.key, ''):
+            logger.warning(
+                f'The {self.key!r} field in hook {dct.get("id")!r} is a '
+                f"regex, not a glob -- matching '/*' probably isn't what you "
+                f'want here',
+            )
+
+
 class MigrateShaToRev:
     key = 'rev'
 
@@ -227,6 +239,8 @@
         for item in MANIFEST_HOOK_DICT.items
         if item.key != 'id'
     ),
+    OptionalSensibleRegex('files', cfgv.check_string),
+    OptionalSensibleRegex('exclude', cfgv.check_string),
 )
 CONFIG_REPO_DICT = cfgv.Map(
     'Repository', 'repo',

{"golden_diff": "diff --git a/pre_commit/clientlib.py b/pre_commit/clientlib.py\n--- a/pre_commit/clientlib.py\n+++ b/pre_commit/clientlib.py\n@@ -112,6 +112,18 @@\n META = 'meta'\n \n \n+class OptionalSensibleRegex(cfgv.OptionalNoDefault):\n+    def check(self, dct: Dict[str, Any]) -> None:\n+        super().check(dct)\n+\n+        if '/*' in dct.get(self.key, ''):\n+            logger.warning(\n+                f'The {self.key!r} field in hook {dct.get(\"id\")!r} is a '\n+                f\"regex, not a glob -- matching '/*' probably isn't what you \"\n+                f'want here',\n+            )\n+\n+\n class MigrateShaToRev:\n     key = 'rev'\n \n@@ -227,6 +239,8 @@\n         for item in MANIFEST_HOOK_DICT.items\n         if item.key != 'id'\n     ),\n+    OptionalSensibleRegex('files', cfgv.check_string),\n+    OptionalSensibleRegex('exclude', cfgv.check_string),\n )\n CONFIG_REPO_DICT = cfgv.Map(\n     'Repository', 'repo',\n", "issue": "Add warning for `files` / `exclude` containing `/*`\nit's a common mistake to believe that those fields are globs, they're not -- they're regular expressions. (and matching `/*` is nonsense, it matches `''`, `'/'` as well as `'//////////////////////////////////////////////////////'`\n", "before_files": [{"content": "import argparse\nimport functools\nimport logging\nimport shlex\nimport sys\nfrom typing import Any\nfrom typing import Dict\nfrom typing import Optional\nfrom typing import Sequence\n\nimport cfgv\nfrom identify.identify import ALL_TAGS\n\nimport pre_commit.constants as C\nfrom pre_commit.color import add_color_option\nfrom pre_commit.errors import FatalError\nfrom pre_commit.languages.all import all_languages\nfrom pre_commit.logging_handler import logging_handler\nfrom pre_commit.util import parse_version\nfrom pre_commit.util import yaml_load\n\nlogger = logging.getLogger('pre_commit')\n\ncheck_string_regex = cfgv.check_and(cfgv.check_string, cfgv.check_regex)\n\n\ndef check_type_tag(tag: str) -> None:\n    if tag not in ALL_TAGS:\n        raise cfgv.ValidationError(\n            f'Type tag {tag!r} is not recognized.  '\n            f'Try upgrading identify and pre-commit?',\n        )\n\n\ndef check_min_version(version: str) -> None:\n    if parse_version(version) > parse_version(C.VERSION):\n        raise cfgv.ValidationError(\n            f'pre-commit version {version} is required but version '\n            f'{C.VERSION} is installed.  '\n            f'Perhaps run `pip install --upgrade pre-commit`.',\n        )\n\n\ndef _make_argparser(filenames_help: str) -> argparse.ArgumentParser:\n    parser = argparse.ArgumentParser()\n    parser.add_argument('filenames', nargs='*', help=filenames_help)\n    parser.add_argument('-V', '--version', action='version', version=C.VERSION)\n    add_color_option(parser)\n    return parser\n\n\nMANIFEST_HOOK_DICT = cfgv.Map(\n    'Hook', 'id',\n\n    cfgv.Required('id', cfgv.check_string),\n    cfgv.Required('name', cfgv.check_string),\n    cfgv.Required('entry', cfgv.check_string),\n    cfgv.Required('language', cfgv.check_one_of(all_languages)),\n    cfgv.Optional('alias', cfgv.check_string, ''),\n\n    cfgv.Optional('files', check_string_regex, ''),\n    cfgv.Optional('exclude', check_string_regex, '^$'),\n    cfgv.Optional('types', cfgv.check_array(check_type_tag), ['file']),\n    cfgv.Optional('types_or', cfgv.check_array(check_type_tag), ['file']),\n    cfgv.Optional('exclude_types', cfgv.check_array(check_type_tag), []),\n\n    cfgv.Optional(\n        'additional_dependencies', cfgv.check_array(cfgv.check_string), [],\n    ),\n    cfgv.Optional('args', cfgv.check_array(cfgv.check_string), []),\n    cfgv.Optional('always_run', cfgv.check_bool, False),\n    cfgv.Optional('pass_filenames', cfgv.check_bool, True),\n    cfgv.Optional('description', cfgv.check_string, ''),\n    cfgv.Optional('language_version', cfgv.check_string, C.DEFAULT),\n    cfgv.Optional('log_file', cfgv.check_string, ''),\n    cfgv.Optional('minimum_pre_commit_version', cfgv.check_string, '0'),\n    cfgv.Optional('require_serial', cfgv.check_bool, False),\n    cfgv.Optional('stages', cfgv.check_array(cfgv.check_one_of(C.STAGES)), []),\n    cfgv.Optional('verbose', cfgv.check_bool, False),\n)\nMANIFEST_SCHEMA = cfgv.Array(MANIFEST_HOOK_DICT)\n\n\nclass InvalidManifestError(FatalError):\n    pass\n\n\nload_manifest = functools.partial(\n    cfgv.load_from_filename,\n    schema=MANIFEST_SCHEMA,\n    load_strategy=yaml_load,\n    exc_tp=InvalidManifestError,\n)\n\n\ndef validate_manifest_main(argv: Optional[Sequence[str]] = None) -> int:\n    parser = _make_argparser('Manifest filenames.')\n    args = parser.parse_args(argv)\n\n    with logging_handler(args.color):\n        ret = 0\n        for filename in args.filenames:\n            try:\n                load_manifest(filename)\n            except InvalidManifestError as e:\n                print(e)\n                ret = 1\n        return ret\n\n\nLOCAL = 'local'\nMETA = 'meta'\n\n\nclass MigrateShaToRev:\n    key = 'rev'\n\n    @staticmethod\n    def _cond(key: str) -> cfgv.Conditional:\n        return cfgv.Conditional(\n            key, cfgv.check_string,\n            condition_key='repo',\n            condition_value=cfgv.NotIn(LOCAL, META),\n            ensure_absent=True,\n        )\n\n    def check(self, dct: Dict[str, Any]) -> None:\n        if dct.get('repo') in {LOCAL, META}:\n            self._cond('rev').check(dct)\n            self._cond('sha').check(dct)\n        elif 'sha' in dct and 'rev' in dct:\n            raise cfgv.ValidationError('Cannot specify both sha and rev')\n        elif 'sha' in dct:\n            self._cond('sha').check(dct)\n        else:\n            self._cond('rev').check(dct)\n\n    def apply_default(self, dct: Dict[str, Any]) -> None:\n        if 'sha' in dct:\n            dct['rev'] = dct.pop('sha')\n\n    remove_default = cfgv.Required.remove_default\n\n\ndef _entry(modname: str) -> str:\n    \"\"\"the hook `entry` is passed through `shlex.split()` by the command\n    runner, so to prevent issues with spaces and backslashes (on Windows)\n    it must be quoted here.\n    \"\"\"\n    return f'{shlex.quote(sys.executable)} -m pre_commit.meta_hooks.{modname}'\n\n\ndef warn_unknown_keys_root(\n        extra: Sequence[str],\n        orig_keys: Sequence[str],\n        dct: Dict[str, str],\n) -> None:\n    logger.warning(f'Unexpected key(s) present at root: {\", \".join(extra)}')\n\n\ndef warn_unknown_keys_repo(\n        extra: Sequence[str],\n        orig_keys: Sequence[str],\n        dct: Dict[str, str],\n) -> None:\n    logger.warning(\n        f'Unexpected key(s) present on {dct[\"repo\"]}: {\", \".join(extra)}',\n    )\n\n\n_meta = (\n    (\n        'check-hooks-apply', (\n            ('name', 'Check hooks apply to the repository'),\n            ('files', C.CONFIG_FILE),\n            ('entry', _entry('check_hooks_apply')),\n        ),\n    ),\n    (\n        'check-useless-excludes', (\n            ('name', 'Check for useless excludes'),\n            ('files', C.CONFIG_FILE),\n            ('entry', _entry('check_useless_excludes')),\n        ),\n    ),\n    (\n        'identity', (\n            ('name', 'identity'),\n            ('verbose', True),\n            ('entry', _entry('identity')),\n        ),\n    ),\n)\n\nMETA_HOOK_DICT = cfgv.Map(\n    'Hook', 'id',\n    cfgv.Required('id', cfgv.check_string),\n    cfgv.Required('id', cfgv.check_one_of(tuple(k for k, _ in _meta))),\n    # language must be system\n    cfgv.Optional('language', cfgv.check_one_of({'system'}), 'system'),\n    *(\n        # default to the hook definition for the meta hooks\n        cfgv.ConditionalOptional(key, cfgv.check_any, value, 'id', hook_id)\n        for hook_id, values in _meta\n        for key, value in values\n    ),\n    *(\n        # default to the \"manifest\" parsing\n        cfgv.OptionalNoDefault(item.key, item.check_fn)\n        # these will always be defaulted above\n        if item.key in {'name', 'language', 'entry'} else\n        item\n        for item in MANIFEST_HOOK_DICT.items\n    ),\n)\nCONFIG_HOOK_DICT = cfgv.Map(\n    'Hook', 'id',\n\n    cfgv.Required('id', cfgv.check_string),\n\n    # All keys in manifest hook dict are valid in a config hook dict, but\n    # are optional.\n    # No defaults are provided here as the config is merged on top of the\n    # manifest.\n    *(\n        cfgv.OptionalNoDefault(item.key, item.check_fn)\n        for item in MANIFEST_HOOK_DICT.items\n        if item.key != 'id'\n    ),\n)\nCONFIG_REPO_DICT = cfgv.Map(\n    'Repository', 'repo',\n\n    cfgv.Required('repo', cfgv.check_string),\n\n    cfgv.ConditionalRecurse(\n        'hooks', cfgv.Array(CONFIG_HOOK_DICT),\n        'repo', cfgv.NotIn(LOCAL, META),\n    ),\n    cfgv.ConditionalRecurse(\n        'hooks', cfgv.Array(MANIFEST_HOOK_DICT),\n        'repo', LOCAL,\n    ),\n    cfgv.ConditionalRecurse(\n        'hooks', cfgv.Array(META_HOOK_DICT),\n        'repo', META,\n    ),\n\n    MigrateShaToRev(),\n    cfgv.WarnAdditionalKeys(('repo', 'rev', 'hooks'), warn_unknown_keys_repo),\n)\nDEFAULT_LANGUAGE_VERSION = cfgv.Map(\n    'DefaultLanguageVersion', None,\n    cfgv.NoAdditionalKeys(all_languages),\n    *(cfgv.Optional(x, cfgv.check_string, C.DEFAULT) for x in all_languages),\n)\nCONFIG_SCHEMA = cfgv.Map(\n    'Config', None,\n\n    cfgv.RequiredRecurse('repos', cfgv.Array(CONFIG_REPO_DICT)),\n    cfgv.OptionalRecurse(\n        'default_language_version', DEFAULT_LANGUAGE_VERSION, {},\n    ),\n    cfgv.Optional(\n        'default_stages',\n        cfgv.check_array(cfgv.check_one_of(C.STAGES)),\n        C.STAGES,\n    ),\n    cfgv.Optional('files', check_string_regex, ''),\n    cfgv.Optional('exclude', check_string_regex, '^$'),\n    cfgv.Optional('fail_fast', cfgv.check_bool, False),\n    cfgv.Optional(\n        'minimum_pre_commit_version',\n        cfgv.check_and(cfgv.check_string, check_min_version),\n        '0',\n    ),\n    cfgv.WarnAdditionalKeys(\n        (\n            'repos',\n            'default_language_version',\n            'default_stages',\n            'files',\n            'exclude',\n            'fail_fast',\n            'minimum_pre_commit_version',\n        ),\n        warn_unknown_keys_root,\n    ),\n)\n\n\nclass InvalidConfigError(FatalError):\n    pass\n\n\ndef ordered_load_normalize_legacy_config(contents: str) -> Dict[str, Any]:\n    data = yaml_load(contents)\n    if isinstance(data, list):\n        logger.warning(\n            'normalizing pre-commit configuration to a top-level map.  '\n            'support for top level list will be removed in a future version.  '\n            'run: `pre-commit migrate-config` to automatically fix this.',\n        )\n        return {'repos': data}\n    else:\n        return data\n\n\nload_config = functools.partial(\n    cfgv.load_from_filename,\n    schema=CONFIG_SCHEMA,\n    load_strategy=ordered_load_normalize_legacy_config,\n    exc_tp=InvalidConfigError,\n)\n\n\ndef validate_config_main(argv: Optional[Sequence[str]] = None) -> int:\n    parser = _make_argparser('Config filenames.')\n    args = parser.parse_args(argv)\n\n    with logging_handler(args.color):\n        ret = 0\n        for filename in args.filenames:\n            try:\n                load_config(filename)\n            except InvalidConfigError as e:\n                print(e)\n                ret = 1\n        return ret\n", "path": "pre_commit/clientlib.py"}], "after_files": [{"content": "import argparse\nimport functools\nimport logging\nimport shlex\nimport sys\nfrom typing import Any\nfrom typing import Dict\nfrom typing import Optional\nfrom typing import Sequence\n\nimport cfgv\nfrom identify.identify import ALL_TAGS\n\nimport pre_commit.constants as C\nfrom pre_commit.color import add_color_option\nfrom pre_commit.errors import FatalError\nfrom pre_commit.languages.all import all_languages\nfrom pre_commit.logging_handler import logging_handler\nfrom pre_commit.util import parse_version\nfrom pre_commit.util import yaml_load\n\nlogger = logging.getLogger('pre_commit')\n\ncheck_string_regex = cfgv.check_and(cfgv.check_string, cfgv.check_regex)\n\n\ndef check_type_tag(tag: str) -> None:\n    if tag not in ALL_TAGS:\n        raise cfgv.ValidationError(\n            f'Type tag {tag!r} is not recognized.  '\n            f'Try upgrading identify and pre-commit?',\n        )\n\n\ndef check_min_version(version: str) -> None:\n    if parse_version(version) > parse_version(C.VERSION):\n        raise cfgv.ValidationError(\n            f'pre-commit version {version} is required but version '\n            f'{C.VERSION} is installed.  '\n            f'Perhaps run `pip install --upgrade pre-commit`.',\n        )\n\n\ndef _make_argparser(filenames_help: str) -> argparse.ArgumentParser:\n    parser = argparse.ArgumentParser()\n    parser.add_argument('filenames', nargs='*', help=filenames_help)\n    parser.add_argument('-V', '--version', action='version', version=C.VERSION)\n    add_color_option(parser)\n    return parser\n\n\nMANIFEST_HOOK_DICT = cfgv.Map(\n    'Hook', 'id',\n\n    cfgv.Required('id', cfgv.check_string),\n    cfgv.Required('name', cfgv.check_string),\n    cfgv.Required('entry', cfgv.check_string),\n    cfgv.Required('language', cfgv.check_one_of(all_languages)),\n    cfgv.Optional('alias', cfgv.check_string, ''),\n\n    cfgv.Optional('files', check_string_regex, ''),\n    cfgv.Optional('exclude', check_string_regex, '^$'),\n    cfgv.Optional('types', cfgv.check_array(check_type_tag), ['file']),\n    cfgv.Optional('types_or', cfgv.check_array(check_type_tag), ['file']),\n    cfgv.Optional('exclude_types', cfgv.check_array(check_type_tag), []),\n\n    cfgv.Optional(\n        'additional_dependencies', cfgv.check_array(cfgv.check_string), [],\n    ),\n    cfgv.Optional('args', cfgv.check_array(cfgv.check_string), []),\n    cfgv.Optional('always_run', cfgv.check_bool, False),\n    cfgv.Optional('pass_filenames', cfgv.check_bool, True),\n    cfgv.Optional('description', cfgv.check_string, ''),\n    cfgv.Optional('language_version', cfgv.check_string, C.DEFAULT),\n    cfgv.Optional('log_file', cfgv.check_string, ''),\n    cfgv.Optional('minimum_pre_commit_version', cfgv.check_string, '0'),\n    cfgv.Optional('require_serial', cfgv.check_bool, False),\n    cfgv.Optional('stages', cfgv.check_array(cfgv.check_one_of(C.STAGES)), []),\n    cfgv.Optional('verbose', cfgv.check_bool, False),\n)\nMANIFEST_SCHEMA = cfgv.Array(MANIFEST_HOOK_DICT)\n\n\nclass InvalidManifestError(FatalError):\n    pass\n\n\nload_manifest = functools.partial(\n    cfgv.load_from_filename,\n    schema=MANIFEST_SCHEMA,\n    load_strategy=yaml_load,\n    exc_tp=InvalidManifestError,\n)\n\n\ndef validate_manifest_main(argv: Optional[Sequence[str]] = None) -> int:\n    parser = _make_argparser('Manifest filenames.')\n    args = parser.parse_args(argv)\n\n    with logging_handler(args.color):\n        ret = 0\n        for filename in args.filenames:\n            try:\n                load_manifest(filename)\n            except InvalidManifestError as e:\n                print(e)\n                ret = 1\n        return ret\n\n\nLOCAL = 'local'\nMETA = 'meta'\n\n\nclass OptionalSensibleRegex(cfgv.OptionalNoDefault):\n    def check(self, dct: Dict[str, Any]) -> None:\n        super().check(dct)\n\n        if '/*' in dct.get(self.key, ''):\n            logger.warning(\n                f'The {self.key!r} field in hook {dct.get(\"id\")!r} is a '\n                f\"regex, not a glob -- matching '/*' probably isn't what you \"\n                f'want here',\n            )\n\n\nclass MigrateShaToRev:\n    key = 'rev'\n\n    @staticmethod\n    def _cond(key: str) -> cfgv.Conditional:\n        return cfgv.Conditional(\n            key, cfgv.check_string,\n            condition_key='repo',\n            condition_value=cfgv.NotIn(LOCAL, META),\n            ensure_absent=True,\n        )\n\n    def check(self, dct: Dict[str, Any]) -> None:\n        if dct.get('repo') in {LOCAL, META}:\n            self._cond('rev').check(dct)\n            self._cond('sha').check(dct)\n        elif 'sha' in dct and 'rev' in dct:\n            raise cfgv.ValidationError('Cannot specify both sha and rev')\n        elif 'sha' in dct:\n            self._cond('sha').check(dct)\n        else:\n            self._cond('rev').check(dct)\n\n    def apply_default(self, dct: Dict[str, Any]) -> None:\n        if 'sha' in dct:\n            dct['rev'] = dct.pop('sha')\n\n    remove_default = cfgv.Required.remove_default\n\n\ndef _entry(modname: str) -> str:\n    \"\"\"the hook `entry` is passed through `shlex.split()` by the command\n    runner, so to prevent issues with spaces and backslashes (on Windows)\n    it must be quoted here.\n    \"\"\"\n    return f'{shlex.quote(sys.executable)} -m pre_commit.meta_hooks.{modname}'\n\n\ndef warn_unknown_keys_root(\n        extra: Sequence[str],\n        orig_keys: Sequence[str],\n        dct: Dict[str, str],\n) -> None:\n    logger.warning(f'Unexpected key(s) present at root: {\", \".join(extra)}')\n\n\ndef warn_unknown_keys_repo(\n        extra: Sequence[str],\n        orig_keys: Sequence[str],\n        dct: Dict[str, str],\n) -> None:\n    logger.warning(\n        f'Unexpected key(s) present on {dct[\"repo\"]}: {\", \".join(extra)}',\n    )\n\n\n_meta = (\n    (\n        'check-hooks-apply', (\n            ('name', 'Check hooks apply to the repository'),\n            ('files', C.CONFIG_FILE),\n            ('entry', _entry('check_hooks_apply')),\n        ),\n    ),\n    (\n        'check-useless-excludes', (\n            ('name', 'Check for useless excludes'),\n            ('files', C.CONFIG_FILE),\n            ('entry', _entry('check_useless_excludes')),\n        ),\n    ),\n    (\n        'identity', (\n            ('name', 'identity'),\n            ('verbose', True),\n            ('entry', _entry('identity')),\n        ),\n    ),\n)\n\nMETA_HOOK_DICT = cfgv.Map(\n    'Hook', 'id',\n    cfgv.Required('id', cfgv.check_string),\n    cfgv.Required('id', cfgv.check_one_of(tuple(k for k, _ in _meta))),\n    # language must be system\n    cfgv.Optional('language', cfgv.check_one_of({'system'}), 'system'),\n    *(\n        # default to the hook definition for the meta hooks\n        cfgv.ConditionalOptional(key, cfgv.check_any, value, 'id', hook_id)\n        for hook_id, values in _meta\n        for key, value in values\n    ),\n    *(\n        # default to the \"manifest\" parsing\n        cfgv.OptionalNoDefault(item.key, item.check_fn)\n        # these will always be defaulted above\n        if item.key in {'name', 'language', 'entry'} else\n        item\n        for item in MANIFEST_HOOK_DICT.items\n    ),\n)\nCONFIG_HOOK_DICT = cfgv.Map(\n    'Hook', 'id',\n\n    cfgv.Required('id', cfgv.check_string),\n\n    # All keys in manifest hook dict are valid in a config hook dict, but\n    # are optional.\n    # No defaults are provided here as the config is merged on top of the\n    # manifest.\n    *(\n        cfgv.OptionalNoDefault(item.key, item.check_fn)\n        for item in MANIFEST_HOOK_DICT.items\n        if item.key != 'id'\n    ),\n    OptionalSensibleRegex('files', cfgv.check_string),\n    OptionalSensibleRegex('exclude', cfgv.check_string),\n)\nCONFIG_REPO_DICT = cfgv.Map(\n    'Repository', 'repo',\n\n    cfgv.Required('repo', cfgv.check_string),\n\n    cfgv.ConditionalRecurse(\n        'hooks', cfgv.Array(CONFIG_HOOK_DICT),\n        'repo', cfgv.NotIn(LOCAL, META),\n    ),\n    cfgv.ConditionalRecurse(\n        'hooks', cfgv.Array(MANIFEST_HOOK_DICT),\n        'repo', LOCAL,\n    ),\n    cfgv.ConditionalRecurse(\n        'hooks', cfgv.Array(META_HOOK_DICT),\n        'repo', META,\n    ),\n\n    MigrateShaToRev(),\n    cfgv.WarnAdditionalKeys(('repo', 'rev', 'hooks'), warn_unknown_keys_repo),\n)\nDEFAULT_LANGUAGE_VERSION = cfgv.Map(\n    'DefaultLanguageVersion', None,\n    cfgv.NoAdditionalKeys(all_languages),\n    *(cfgv.Optional(x, cfgv.check_string, C.DEFAULT) for x in all_languages),\n)\nCONFIG_SCHEMA = cfgv.Map(\n    'Config', None,\n\n    cfgv.RequiredRecurse('repos', cfgv.Array(CONFIG_REPO_DICT)),\n    cfgv.OptionalRecurse(\n        'default_language_version', DEFAULT_LANGUAGE_VERSION, {},\n    ),\n    cfgv.Optional(\n        'default_stages',\n        cfgv.check_array(cfgv.check_one_of(C.STAGES)),\n        C.STAGES,\n    ),\n    cfgv.Optional('files', check_string_regex, ''),\n    cfgv.Optional('exclude', check_string_regex, '^$'),\n    cfgv.Optional('fail_fast', cfgv.check_bool, False),\n    cfgv.Optional(\n        'minimum_pre_commit_version',\n        cfgv.check_and(cfgv.check_string, check_min_version),\n        '0',\n    ),\n    cfgv.WarnAdditionalKeys(\n        (\n            'repos',\n            'default_language_version',\n            'default_stages',\n            'files',\n            'exclude',\n            'fail_fast',\n            'minimum_pre_commit_version',\n        ),\n        warn_unknown_keys_root,\n    ),\n)\n\n\nclass InvalidConfigError(FatalError):\n    pass\n\n\ndef ordered_load_normalize_legacy_config(contents: str) -> Dict[str, Any]:\n    data = yaml_load(contents)\n    if isinstance(data, list):\n        logger.warning(\n            'normalizing pre-commit configuration to a top-level map.  '\n            'support for top level list will be removed in a future version.  '\n            'run: `pre-commit migrate-config` to automatically fix this.',\n        )\n        return {'repos': data}\n    else:\n        return data\n\n\nload_config = functools.partial(\n    cfgv.load_from_filename,\n    schema=CONFIG_SCHEMA,\n    load_strategy=ordered_load_normalize_legacy_config,\n    exc_tp=InvalidConfigError,\n)\n\n\ndef validate_config_main(argv: Optional[Sequence[str]] = None) -> int:\n    parser = _make_argparser('Config filenames.')\n    args = parser.parse_args(argv)\n\n    with logging_handler(args.color):\n        ret = 0\n        for filename in args.filenames:\n            try:\n                load_config(filename)\n            except InvalidConfigError as e:\n                print(e)\n                ret = 1\n        return ret\n", "path": "pre_commit/clientlib.py"}]}