Page Menu
Home
WickedGov Phorge
Search
Configure Global Search
Log In
Files
F1431234
LintCommand.php
No One
Temporary
Actions
Download File
Edit File
Delete File
View Transforms
Subscribe
Flag For Later
Award Token
Size
9 KB
Referenced Files
None
Subscribers
None
LintCommand.php
View Options
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace
Symfony\Component\Yaml\Command
;
use
Symfony\Component\Console\CI\GithubActionReporter
;
use
Symfony\Component\Console\Command\Command
;
use
Symfony\Component\Console\Completion\CompletionInput
;
use
Symfony\Component\Console\Completion\CompletionSuggestions
;
use
Symfony\Component\Console\Exception\InvalidArgumentException
;
use
Symfony\Component\Console\Exception\RuntimeException
;
use
Symfony\Component\Console\Input\InputArgument
;
use
Symfony\Component\Console\Input\InputInterface
;
use
Symfony\Component\Console\Input\InputOption
;
use
Symfony\Component\Console\Output\OutputInterface
;
use
Symfony\Component\Console\Style\SymfonyStyle
;
use
Symfony\Component\Yaml\Exception\ParseException
;
use
Symfony\Component\Yaml\Parser
;
use
Symfony\Component\Yaml\Yaml
;
/**
* Validates YAML files syntax and outputs encountered errors.
*
* @author Grégoire Pineau <lyrixx@lyrixx.info>
* @author Robin Chalas <robin.chalas@gmail.com>
*/
class
LintCommand
extends
Command
{
protected
static
$defaultName
=
'lint:yaml'
;
protected
static
$defaultDescription
=
'Lint a YAML file and outputs encountered errors'
;
private
$parser
;
private
$format
;
private
$displayCorrectFiles
;
private
$directoryIteratorProvider
;
private
$isReadableProvider
;
public
function
__construct
(?
string
$name
=
null
,
?
callable
$directoryIteratorProvider
=
null
,
?
callable
$isReadableProvider
=
null
)
{
parent
::
__construct
(
$name
);
$this
->
directoryIteratorProvider
=
$directoryIteratorProvider
;
$this
->
isReadableProvider
=
$isReadableProvider
;
}
/**
* {@inheritdoc}
*/
protected
function
configure
()
{
$this
->
setDescription
(
self
::
$defaultDescription
)
->
addArgument
(
'filename'
,
InputArgument
::
IS_ARRAY
,
'A file, a directory or "-" for reading from STDIN'
)
->
addOption
(
'format'
,
null
,
InputOption
::
VALUE_REQUIRED
,
'The output format'
)
->
addOption
(
'exclude'
,
null
,
InputOption
::
VALUE_REQUIRED
|
InputOption
::
VALUE_IS_ARRAY
,
'Path(s) to exclude'
)
->
addOption
(
'parse-tags'
,
null
,
InputOption
::
VALUE_NEGATABLE
,
'Parse custom tags'
,
null
)
->
setHelp
(
<<<EOF
The <info>%command.name%</info> command lints a YAML file and outputs to STDOUT
the first encountered syntax error.
You can validates YAML contents passed from STDIN:
<info>cat filename | php %command.full_name% -</info>
You can also validate the syntax of a file:
<info>php %command.full_name% filename</info>
Or of a whole directory:
<info>php %command.full_name% dirname</info>
<info>php %command.full_name% dirname --format=json</info>
You can also exclude one or more specific files:
<info>php %command.full_name% dirname --exclude="dirname/foo.yaml" --exclude="dirname/bar.yaml"</info>
EOF
)
;
}
protected
function
execute
(
InputInterface
$input
,
OutputInterface
$output
)
{
$io
=
new
SymfonyStyle
(
$input
,
$output
);
$filenames
=
(
array
)
$input
->
getArgument
(
'filename'
);
$excludes
=
$input
->
getOption
(
'exclude'
);
$this
->
format
=
$input
->
getOption
(
'format'
);
$flags
=
$input
->
getOption
(
'parse-tags'
);
if
(
'github'
===
$this
->
format
&&
!
class_exists
(
GithubActionReporter
::
class
))
{
throw
new
\InvalidArgumentException
(
'The "github" format is only available since "symfony/console" >= 5.3.'
);
}
if
(
null
===
$this
->
format
)
{
// Autodetect format according to CI environment
$this
->
format
=
class_exists
(
GithubActionReporter
::
class
)
&&
GithubActionReporter
::
isGithubActionEnvironment
()
?
'github'
:
'txt'
;
}
$flags
=
$flags
?
Yaml
::
PARSE_CUSTOM_TAGS
:
0
;
$this
->
displayCorrectFiles
=
$output
->
isVerbose
();
if
([
'-'
]
===
$filenames
)
{
return
$this
->
display
(
$io
,
[
$this
->
validate
(
file_get_contents
(
'php://stdin'
),
$flags
)]);
}
if
(!
$filenames
)
{
throw
new
RuntimeException
(
'Please provide a filename or pipe file content to STDIN.'
);
}
$filesInfo
=
[];
foreach
(
$filenames
as
$filename
)
{
if
(!
$this
->
isReadable
(
$filename
))
{
throw
new
RuntimeException
(
sprintf
(
'File or directory "%s" is not readable.'
,
$filename
));
}
foreach
(
$this
->
getFiles
(
$filename
)
as
$file
)
{
if
(!
\in_array
(
$file
->
getPathname
(),
$excludes
,
true
))
{
$filesInfo
[]
=
$this
->
validate
(
file_get_contents
(
$file
),
$flags
,
$file
);
}
}
}
return
$this
->
display
(
$io
,
$filesInfo
);
}
private
function
validate
(
string
$content
,
int
$flags
,
?
string
$file
=
null
)
{
$prevErrorHandler
=
set_error_handler
(
function
(
$level
,
$message
,
$file
,
$line
)
use
(&
$prevErrorHandler
)
{
if
(
\E_USER_DEPRECATED
===
$level
)
{
throw
new
ParseException
(
$message
,
$this
->
getParser
()->
getRealCurrentLineNb
()
+
1
);
}
return
$prevErrorHandler
?
$prevErrorHandler
(
$level
,
$message
,
$file
,
$line
)
:
false
;
});
try
{
$this
->
getParser
()->
parse
(
$content
,
Yaml
::
PARSE_CONSTANT
|
$flags
);
}
catch
(
ParseException
$e
)
{
return
[
'file'
=>
$file
,
'line'
=>
$e
->
getParsedLine
(),
'valid'
=>
false
,
'message'
=>
$e
->
getMessage
()];
}
finally
{
restore_error_handler
();
}
return
[
'file'
=>
$file
,
'valid'
=>
true
];
}
private
function
display
(
SymfonyStyle
$io
,
array
$files
):
int
{
switch
(
$this
->
format
)
{
case
'txt'
:
return
$this
->
displayTxt
(
$io
,
$files
);
case
'json'
:
return
$this
->
displayJson
(
$io
,
$files
);
case
'github'
:
return
$this
->
displayTxt
(
$io
,
$files
,
true
);
default
:
throw
new
InvalidArgumentException
(
sprintf
(
'The format "%s" is not supported.'
,
$this
->
format
));
}
}
private
function
displayTxt
(
SymfonyStyle
$io
,
array
$filesInfo
,
bool
$errorAsGithubAnnotations
=
false
):
int
{
$countFiles
=
\count
(
$filesInfo
);
$erroredFiles
=
0
;
$suggestTagOption
=
false
;
if
(
$errorAsGithubAnnotations
)
{
$githubReporter
=
new
GithubActionReporter
(
$io
);
}
foreach
(
$filesInfo
as
$info
)
{
if
(
$info
[
'valid'
]
&&
$this
->
displayCorrectFiles
)
{
$io
->
comment
(
'<info>OK</info>'
.(
$info
[
'file'
]
?
sprintf
(
' in %s'
,
$info
[
'file'
])
:
''
));
}
elseif
(!
$info
[
'valid'
])
{
++
$erroredFiles
;
$io
->
text
(
'<error> ERROR </error>'
.(
$info
[
'file'
]
?
sprintf
(
' in %s'
,
$info
[
'file'
])
:
''
));
$io
->
text
(
sprintf
(
'<error> >> %s</error>'
,
$info
[
'message'
]));
if
(
false
!==
strpos
(
$info
[
'message'
],
'PARSE_CUSTOM_TAGS'
))
{
$suggestTagOption
=
true
;
}
if
(
$errorAsGithubAnnotations
)
{
$githubReporter
->
error
(
$info
[
'message'
],
$info
[
'file'
]
??
'php://stdin'
,
$info
[
'line'
]);
}
}
}
if
(
0
===
$erroredFiles
)
{
$io
->
success
(
sprintf
(
'All %d YAML files contain valid syntax.'
,
$countFiles
));
}
else
{
$io
->
warning
(
sprintf
(
'%d YAML files have valid syntax and %d contain errors.%s'
,
$countFiles
-
$erroredFiles
,
$erroredFiles
,
$suggestTagOption
?
' Use the --parse-tags option if you want parse custom tags.'
:
''
));
}
return
min
(
$erroredFiles
,
1
);
}
private
function
displayJson
(
SymfonyStyle
$io
,
array
$filesInfo
):
int
{
$errors
=
0
;
array_walk
(
$filesInfo
,
function
(&
$v
)
use
(&
$errors
)
{
$v
[
'file'
]
=
(
string
)
$v
[
'file'
];
if
(!
$v
[
'valid'
])
{
++
$errors
;
}
if
(
isset
(
$v
[
'message'
])
&&
false
!==
strpos
(
$v
[
'message'
],
'PARSE_CUSTOM_TAGS'
))
{
$v
[
'message'
]
.=
' Use the --parse-tags option if you want parse custom tags.'
;
}
});
$io
->
writeln
(
json_encode
(
$filesInfo
,
\JSON_PRETTY_PRINT
|
\JSON_UNESCAPED_SLASHES
));
return
min
(
$errors
,
1
);
}
private
function
getFiles
(
string
$fileOrDirectory
):
iterable
{
if
(
is_file
(
$fileOrDirectory
))
{
yield
new
\SplFileInfo
(
$fileOrDirectory
);
return
;
}
foreach
(
$this
->
getDirectoryIterator
(
$fileOrDirectory
)
as
$file
)
{
if
(!
\in_array
(
$file
->
getExtension
(),
[
'yml'
,
'yaml'
]))
{
continue
;
}
yield
$file
;
}
}
private
function
getParser
():
Parser
{
if
(!
$this
->
parser
)
{
$this
->
parser
=
new
Parser
();
}
return
$this
->
parser
;
}
private
function
getDirectoryIterator
(
string
$directory
):
iterable
{
$default
=
function
(
$directory
)
{
return
new
\RecursiveIteratorIterator
(
new
\RecursiveDirectoryIterator
(
$directory
,
\FilesystemIterator
::
SKIP_DOTS
|
\FilesystemIterator
::
FOLLOW_SYMLINKS
),
\RecursiveIteratorIterator
::
LEAVES_ONLY
);
};
if
(
null
!==
$this
->
directoryIteratorProvider
)
{
return
(
$this
->
directoryIteratorProvider
)(
$directory
,
$default
);
}
return
$default
(
$directory
);
}
private
function
isReadable
(
string
$fileOrDirectory
):
bool
{
$default
=
function
(
$fileOrDirectory
)
{
return
is_readable
(
$fileOrDirectory
);
};
if
(
null
!==
$this
->
isReadableProvider
)
{
return
(
$this
->
isReadableProvider
)(
$fileOrDirectory
,
$default
);
}
return
$default
(
$fileOrDirectory
);
}
public
function
complete
(
CompletionInput
$input
,
CompletionSuggestions
$suggestions
):
void
{
if
(
$input
->
mustSuggestOptionValuesFor
(
'format'
))
{
$suggestions
->
suggestValues
([
'txt'
,
'json'
,
'github'
]);
}
}
}
File Metadata
Details
Attached
Mime Type
text/x-php
Expires
Sat, May 16, 20:13 (23 h, 3 m)
Storage Engine
local-disk
Storage Format
Raw Data
Storage Handle
58/d9/3b48add9772bc4820ea5cc13dd63
Default Alt Text
LintCommand.php (9 KB)
Attached To
Mode
rMWPROD MediaWiki Production
Attached
Detach File
Event Timeline
Log In to Comment