33
44import argparse
55import functools
6+ import pipes
7+ import sys
68
79import cfgv
810from aspy .yaml import ordered_load
@@ -88,8 +90,8 @@ def validate_manifest_main(argv=None):
8890 return ret
8991
9092
91- _LOCAL_SENTINEL = 'local'
92- _META_SENTINEL = 'meta'
93+ _LOCAL = 'local'
94+ _META = 'meta'
9395
9496
9597class MigrateShaToRev (object ):
@@ -98,12 +100,12 @@ def _cond(key):
98100 return cfgv .Conditional (
99101 key , cfgv .check_string ,
100102 condition_key = 'repo' ,
101- condition_value = cfgv .NotIn (_LOCAL_SENTINEL , _META_SENTINEL ),
103+ condition_value = cfgv .NotIn (_LOCAL , _META ),
102104 ensure_absent = True ,
103105 )
104106
105107 def check (self , dct ):
106- if dct .get ('repo' ) in {_LOCAL_SENTINEL , _META_SENTINEL }:
108+ if dct .get ('repo' ) in {_LOCAL , _META }:
107109 self ._cond ('rev' ).check (dct )
108110 self ._cond ('sha' ).check (dct )
109111 elif 'sha' in dct and 'rev' in dct :
@@ -121,6 +123,61 @@ def remove_default(self, dct):
121123 pass
122124
123125
126+ def _entry (modname ):
127+ """the hook `entry` is passed through `shlex.split()` by the command
128+ runner, so to prevent issues with spaces and backslashes (on Windows)
129+ it must be quoted here.
130+ """
131+ return '{} -m pre_commit.meta_hooks.{}' .format (
132+ pipes .quote (sys .executable ), modname ,
133+ )
134+
135+
136+ _meta = (
137+ (
138+ 'check-hooks-apply' , (
139+ ('name' , 'Check hooks apply to the repository' ),
140+ ('files' , C .CONFIG_FILE ),
141+ ('entry' , _entry ('check_hooks_apply' )),
142+ ),
143+ ),
144+ (
145+ 'check-useless-excludes' , (
146+ ('name' , 'Check for useless excludes' ),
147+ ('files' , C .CONFIG_FILE ),
148+ ('entry' , _entry ('check_useless_excludes' )),
149+ ),
150+ ),
151+ (
152+ 'identity' , (
153+ ('name' , 'identity' ),
154+ ('verbose' , True ),
155+ ('entry' , _entry ('identity' )),
156+ ),
157+ ),
158+ )
159+
160+ META_HOOK_DICT = cfgv .Map (
161+ 'Hook' , 'id' ,
162+ * ([
163+ cfgv .Required ('id' , cfgv .check_string ),
164+ cfgv .Required ('id' , cfgv .check_one_of (tuple (k for k , _ in _meta ))),
165+ # language must be system
166+ cfgv .Optional ('language' , cfgv .check_one_of ({'system' }), 'system' ),
167+ ] + [
168+ # default to the hook definition for the meta hooks
169+ cfgv .ConditionalOptional (key , cfgv .check_any , value , 'id' , hook_id )
170+ for hook_id , values in _meta
171+ for key , value in values
172+ ] + [
173+ # default to the "manifest" parsing
174+ cfgv .OptionalNoDefault (item .key , item .check_fn )
175+ # these will always be defaulted above
176+ if item .key in {'name' , 'language' , 'entry' } else
177+ item
178+ for item in MANIFEST_HOOK_DICT .items
179+ ])
180+ )
124181CONFIG_HOOK_DICT = cfgv .Map (
125182 'Hook' , 'id' ,
126183
@@ -140,7 +197,19 @@ def remove_default(self, dct):
140197 'Repository' , 'repo' ,
141198
142199 cfgv .Required ('repo' , cfgv .check_string ),
143- cfgv .RequiredRecurse ('hooks' , cfgv .Array (CONFIG_HOOK_DICT )),
200+
201+ cfgv .ConditionalRecurse (
202+ 'hooks' , cfgv .Array (CONFIG_HOOK_DICT ),
203+ 'repo' , cfgv .NotIn (_LOCAL , _META ),
204+ ),
205+ cfgv .ConditionalRecurse (
206+ 'hooks' , cfgv .Array (MANIFEST_HOOK_DICT ),
207+ 'repo' , _LOCAL ,
208+ ),
209+ cfgv .ConditionalRecurse (
210+ 'hooks' , cfgv .Array (META_HOOK_DICT ),
211+ 'repo' , _META ,
212+ ),
144213
145214 MigrateShaToRev (),
146215)
@@ -154,11 +223,11 @@ def remove_default(self, dct):
154223
155224
156225def is_local_repo (repo_entry ):
157- return repo_entry ['repo' ] == _LOCAL_SENTINEL
226+ return repo_entry ['repo' ] == _LOCAL
158227
159228
160229def is_meta_repo (repo_entry ):
161- return repo_entry ['repo' ] == _META_SENTINEL
230+ return repo_entry ['repo' ] == _META
162231
163232
164233class InvalidConfigError (FatalError ):
0 commit comments