Page Menu
Home
Phorge
Search
Configure Global Search
Log In
Files
F2893044
ArcanistConfigurationDrivenLintEngine.php
No One
Temporary
Actions
Download File
Edit File
Delete File
View Transforms
Subscribe
Award Token
Flag For Later
Advanced/Developer...
View Handle
View Hovercard
Size
5 KB
Referenced Files
None
Subscribers
None
ArcanistConfigurationDrivenLintEngine.php
View Options
<?php
final
class
ArcanistConfigurationDrivenLintEngine
extends
ArcanistLintEngine
{
public
function
buildLinters
(
)
{
$working_copy
=
$this
->
getWorkingCopy
(
)
;
$config_path
=
$working_copy
->
getProjectPath
(
'.arclint'
)
;
if
(
!
Filesystem
::
pathExists
(
$config_path
)
)
{
throw
new
ArcanistUsageException
(
pht
(
"Unable to find '%s' file to configure linters. Create an "
.
"'%s' file in the root directory of the working copy."
,
'.arclint'
,
'.arclint'
)
)
;
}
$data
=
Filesystem
::
readFile
(
$config_path
)
;
$config
=
null
;
try
{
$config
=
phutil_json_decode
(
$data
)
;
}
catch
(
PhutilJSONParserException
$ex
)
{
throw
new
PhutilProxyException
(
pht
(
"Expected '%s' file to be a valid JSON file, but "
.
"failed to decode '%s'."
,
'.arclint'
,
$config_path
)
,
$ex
)
;
}
$linters
=
$this
->
loadAvailableLinters
(
)
;
try
{
PhutilTypeSpec
::
checkMap
(
$config
,
array
(
'exclude'
=>
'optional regex | list<regex>'
,
'linters'
=>
'map<string, map<string, wild>>'
,
)
)
;
}
catch
(
PhutilTypeCheckException
$ex
)
{
throw
new
PhutilProxyException
(
pht
(
"Error in parsing '%s' file."
,
$config_path
)
,
$ex
)
;
}
$global_exclude
=
(array)
idx
(
$config
,
'exclude'
,
array
(
)
)
;
$built_linters
=
array
(
)
;
$all_paths
=
$this
->
getPaths
(
)
;
foreach
(
$config
[
'linters'
]
as
$name
=>
$spec
)
{
$type
=
idx
(
$spec
,
'type'
)
;
if
(
$type
!==
null
)
{
if
(
empty
(
$linters
[
$type
]
)
)
{
throw
new
ArcanistUsageException
(
pht
(
"Linter '%s' specifies invalid type '%s'. "
.
"Available linters are: %s."
,
$name
,
$type
,
implode
(
', '
,
array_keys
(
$linters
)
)
)
)
;
}
$linter
=
clone
$linters
[
$type
]
;
$linter
->
setEngine
(
$this
)
;
$more
=
$linter
->
getLinterConfigurationOptions
(
)
;
foreach
(
$more
as
$key
=>
$option_spec
)
{
PhutilTypeSpec
::
checkMap
(
$option_spec
,
array
(
'type'
=>
'string'
,
'help'
=>
'string'
,
)
)
;
$more
[
$key
]
=
$option_spec
[
'type'
]
;
}
}
else
{
// We'll raise an error below about the invalid "type" key.
$linter
=
null
;
$more
=
array
(
)
;
}
try
{
PhutilTypeSpec
::
checkMap
(
$spec
,
array
(
'type'
=>
'string'
,
'include'
=>
'optional regex | list<regex>'
,
'exclude'
=>
'optional regex | list<regex>'
,
)
+
$more
)
;
}
catch
(
PhutilTypeCheckException
$ex
)
{
throw
new
PhutilProxyException
(
pht
(
"Error in parsing '%s' file, for linter '%s'."
,
'.arclint'
,
$name
)
,
$ex
)
;
}
foreach
(
$more
as
$key
=>
$value
)
{
if
(
array_key_exists
(
$key
,
$spec
)
)
{
try
{
$linter
->
setLinterConfigurationValue
(
$key
,
$spec
[
$key
]
)
;
}
catch
(
Exception
$ex
)
{
throw
new
PhutilProxyException
(
pht
(
"Error in parsing '%s' file, in key '%s' for linter '%s'."
,
'.arclint'
,
$key
,
$name
)
,
$ex
)
;
}
}
}
$include
=
(array)
idx
(
$spec
,
'include'
,
array
(
)
)
;
$exclude
=
(array)
idx
(
$spec
,
'exclude'
,
array
(
)
)
;
$console
=
PhutilConsole
::
getConsole
(
)
;
$console
->
writeLog
(
"%s\n"
,
pht
(
"Examining paths for linter '%s'."
,
$name
)
)
;
$paths
=
$this
->
matchPaths
(
$all_paths
,
$include
,
$exclude
,
$global_exclude
)
;
$console
->
writeLog
(
"%s\n"
,
pht
(
"Found %d matching paths for linter '%s'."
,
count
(
$paths
)
,
$name
)
)
;
$linter
->
setPaths
(
$paths
)
;
$built_linters
[
]
=
$linter
;
}
return
$built_linters
;
}
private
function
loadAvailableLinters
(
)
{
$linters
=
id
(
new
PhutilSymbolLoader
(
)
)
->
setAncestorClass
(
'ArcanistLinter'
)
->
loadObjects
(
)
;
$map
=
array
(
)
;
foreach
(
$linters
as
$linter
)
{
$name
=
$linter
->
getLinterConfigurationName
(
)
;
// This linter isn't selectable through configuration.
if
(
$name
===
null
)
{
continue
;
}
if
(
empty
(
$map
[
$name
]
)
)
{
$map
[
$name
]
=
$linter
;
continue
;
}
$orig_class
=
get_class
(
$map
[
$name
]
)
;
$this_class
=
get_class
(
$linter
)
;
throw
new
Exception
(
pht
(
"Two linters (`%s`, `%s`) both have the same configuration "
.
"name ('%s'). Linters must have unique configuration names."
,
$orig_class
,
$this_class
,
$name
)
)
;
}
return
$map
;
}
private
function
matchPaths
(
array
$paths
,
array
$include
,
array
$exclude
,
array
$global_exclude
)
{
$console
=
PhutilConsole
::
getConsole
(
)
;
$match
=
array
(
)
;
foreach
(
$paths
as
$path
)
{
$keep
=
false
;
if
(
!
$include
)
{
$keep
=
true
;
}
else
{
foreach
(
$include
as
$rule
)
{
if
(
preg_match
(
$rule
,
$path
)
)
{
$keep
=
true
;
break
;
}
}
}
if
(
!
$keep
)
{
continue
;
}
if
(
$exclude
)
{
foreach
(
$exclude
as
$rule
)
{
if
(
preg_match
(
$rule
,
$path
)
)
{
continue
2
;
}
}
}
if
(
$global_exclude
)
{
foreach
(
$global_exclude
as
$rule
)
{
if
(
preg_match
(
$rule
,
$path
)
)
{
continue
2
;
}
}
}
$match
[
]
=
$path
;
}
return
$match
;
}
}
File Metadata
Details
Attached
Mime Type
text/x-php
Expires
Sun, Jan 19, 17:46 (1 w, 5 d ago)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
1127106
Default Alt Text
ArcanistConfigurationDrivenLintEngine.php (5 KB)
Attached To
Mode
rARC Arcanist
Attached
Detach File
Event Timeline
Log In to Comment