55
66from pkgcore .ebuild .eapi import EAPI
77from snakeoil .demandload import demand_compile_regexp
8+ from snakeoil .klass import jit_attr
9+ from snakeoil .mappings import ImmutableDict
810from snakeoil .strings import pluralism as _pl
911
1012from .. import base
@@ -85,15 +87,19 @@ def feed(self, entry):
8587 yield HttpsAvailable (link , lines , pkg = pkg )
8688
8789
88- class PortageInternals (base .VersionedResult , base . Warning ):
89- """Ebuild uses a function or variable internal to portage ."""
90+ class _CommandResult (base .VersionedResult ):
91+ """Generic command result ."""
9092
9193 def __init__ (self , command , line , lineno , ** kwargs ):
9294 super ().__init__ (** kwargs )
9395 self .command = command
9496 self .line = line
9597 self .lineno = lineno
9698
99+
100+ class PortageInternals (_CommandResult , base .Warning ):
101+ """Ebuild uses a function or variable internal to portage."""
102+
97103 @property
98104 def desc (self ):
99105 s = f'{ self .command !r} , used on line { self .lineno } '
@@ -102,15 +108,12 @@ def desc(self):
102108 return s
103109
104110
105- class _EapiCommandResult (base . VersionedResult ):
111+ class _EapiCommandResult (_CommandResult ):
106112 """Generic EAPI command result."""
107113
108- def __init__ (self , command , eapi , line , lineno , ** kwargs ):
109- super ().__init__ (** kwargs )
110- self .command = command
114+ def __init__ (self , * args , eapi , ** kwargs ):
115+ super ().__init__ (* args , ** kwargs )
111116 self .eapi = eapi
112- self .line = line
113- self .lineno = lineno
114117
115118 @property
116119 def desc (self ):
@@ -151,21 +154,29 @@ class BadCommandsCheck(base.Check):
151154
152155 CMD_USAGE_REGEX = r'^(\s*|.*[|&{{(]+\s*)\b(?P<cmd>{})(?!\.)\b'
153156
154- def __init__ (self , options ):
155- super ().__init__ (options )
156- self .internals_re = self ._cmds_regex (self .INTERNALS )
157- self .banned_eapi_cmds = {}
158- self .deprecated_eapi_cmds = {}
157+ def _cmds_regex (self , cmds ):
158+ return re .compile (self .CMD_USAGE_REGEX .format (r'|' .join (cmds )))
159+
160+ @jit_attr
161+ def regexes (self ):
162+ d = {}
163+ internals_re = self ._cmds_regex (self .INTERNALS )
159164 for eapi_str , eapi in EAPI .known_eapis .items ():
165+ regexes = [(internals_re , PortageInternals , {})]
160166 if eapi .bash_cmds_banned :
161- self .banned_eapi_cmds [eapi_str ] = self ._cmds_regex (
162- eapi .bash_cmds_banned )
167+ regexes .append ((
168+ self ._cmds_regex (eapi .bash_cmds_banned ),
169+ BannedEapiCommand ,
170+ {'eapi' : eapi_str },
171+ ))
163172 if eapi .bash_cmds_deprecated :
164- self .deprecated_eapi_cmds [eapi_str ] = self ._cmds_regex (
165- eapi .bash_cmds_deprecated )
166-
167- def _cmds_regex (self , cmds ):
168- return re .compile (self .CMD_USAGE_REGEX .format (r'|' .join (cmds )))
173+ regexes .append ((
174+ self ._cmds_regex (eapi .bash_cmds_deprecated ),
175+ DeprecatedEapiCommand ,
176+ {'eapi' : eapi_str },
177+ ))
178+ d [eapi_str ] = tuple (regexes )
179+ return ImmutableDict (d )
169180
170181 def feed (self , entry ):
171182 pkg , lines = entry
@@ -174,21 +185,11 @@ def feed(self, entry):
174185 if not line :
175186 continue
176187 if line [0 ] != '#' :
177- # searching for multiple matches on a single line is too slow
178- matches = self .internals_re .match (line )
179- if matches is not None :
180- yield PortageInternals (matches .group ('cmd' ), line , lineno , pkg = pkg )
181- eapi = str (pkg .eapi )
182- banned_eapi_cmds_re = self .banned_eapi_cmds .get (eapi )
183- if banned_eapi_cmds_re is not None :
184- matches = banned_eapi_cmds_re .match (line )
185- if matches is not None :
186- yield BannedEapiCommand (matches .group ('cmd' ), eapi , line , lineno , pkg = pkg )
187- deprecated_eapi_cmds_re = self .deprecated_eapi_cmds .get (eapi )
188- if deprecated_eapi_cmds_re is not None :
189- matches = deprecated_eapi_cmds_re .match (line )
190- if matches is not None :
191- yield DeprecatedEapiCommand (matches .group ('cmd' ), eapi , line , lineno , pkg = pkg )
188+ eapi_str = str (pkg .eapi )
189+ for regex , result_cls , kwargs in self .regexes [eapi_str ]:
190+ match = regex .match (line )
191+ if match is not None :
192+ yield result_cls (match .group ('cmd' ), line , lineno , pkg = pkg , ** kwargs )
192193
193194
194195class MissingSlash (base .VersionedResult , base .Error ):
0 commit comments