10000 feature #9666 [FrameworkBundle] Added a yaml:lint command (lyrixx) · symfony/symfony@f3670b4 · GitHub
[go: up one dir, main page]

Skip to content

Commit f3670b4

Browse files
committed
feature #9666 [FrameworkBundle] Added a yaml:lint command (lyrixx)
This PR was merged into the 2.5-dev branch. Discussion ---------- [FrameworkBundle] Added a yaml:lint command | Q | A | ------------- | --- | Bug fix? | no | New feature? | yes | BC breaks? | no | Deprecations? | no | Tests pass? | yes | Fixed tickets | #9645 | License | MIT | Doc PR | n/a Commits ------- 9c06b27 [FrameworkBundle] Added yaml:lint command
2 parents 8cd8ec0 + 9c06b27 commit f3670b4

File tree

2 files changed

+163
-0
lines changed

2 files changed

+163
-0
lines changed

src/Symfony/Bundle/FrameworkBundle/CHANGELOG.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,11 @@
11
CHANGELOG
22
=========
33

4+
2.5.0
5+
-----
6+
7+
* Added `yaml:lint` command
8+
49
2.4.0
510
-----
611

Lines changed: 158 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,158 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <fabien@symfony.com>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Symfony\Bundle\FrameworkBundle\Command;
13+
14+
use Symfony\Component\Console\Command\Command;
15+
use Symfony\Component\Console\Input\InputInterface;
16+
use Symfony\Component\Console\Input\InputOption;
17+
use Symfony\Component\Console\Output\OutputInterface;
18+
use Symfony\Component\Finder\Finder;
19+
use Symfony\Component\Yaml\Exception\ParseException;
20+
use Symfony\Component\Yaml\Parser;
21+
22+
/**
23+
* Validates YAML files syntax and output encountered errors.
24+
*
25+
* @author Grégoire Pineau <lyrixx@lyrixx.info>
26+
*/
27+
class YamlLintCommand extends Command
28+
{
29+
protected function configure()
30+
{
31+
$this
32+
->setName('yaml:lint')
33+
->setDescription('Lints a file and outputs encountered errors')
34+
->addArgument('filename', null, 'A file or a directory or STDIN')
35+
->addOption('format', null, InputOption::VALUE_REQUIRED, 'The output format', 'txt')
36+
->setHelp(<<<EOF
37+
The <info>%command.name%</info> command lints a YAML file and outputs to STDOUT
38+
the first encountered syntax error.
39+
40+
You can validate the syntax of a file:
41+
42+
<info>php %command.full_name% filename</info>
43+
44+
Or of a whole directory:
45+
46+
<info>php %command.full_name% dirname</info>
47+
<info>php %command.full_name% dirname --format=json</info>
48+
49+
Or all YAML files in a bundle:
50+
51+
<info>php %command.full_name% @AcmeDemoBundle</info>
52+
53+
You can also pass the YAML contents from STDIN:
54+
55+
<info>cat filename | php %command.full_name%</info>
56+
EOF
57+
)
58+
;
59+
}
60+
61+
protected function execute(InputInterface $input, OutputInterface $output)
62+
{
63+
$filename = $input->getArgument('filename');
64+
65+
if (!$filename) {
66+
if (0 !== ftell(STDIN)) {
67+
throw new \RuntimeException('Please provide a filename or pipe file content to STDIN.');
68+
}
69+
70+
$content = '';
71+
while (!feof(STDIN)) {
72+
$content .= fread(STDIN, 1024);
73+
}
74+
75+
return $this->display($input, $output, array($this->validate($content)));
76+
}
77+
78+
if (0 !== strpos($filename, '@') && !is_readable($filename)) {
79+
throw new \RuntimeException(sprintf('File or directory "%s" is not readable', $filename));
80+
}
81+
82+
$files = array();
83+
if (is_file($filename)) {
84+
$files = array($filename);
85+
} elseif (is_dir($filename)) {
86+
$files = Finder::create()->files()->in($filename)->name('*.yml');
87+
} els 341A e {
88+
$dir = $this->getApplication()->getKernel()->locateResource($filename);
89+
$files = Finder::create()->files()->in($dir)->name('*.yml');
90+
}
91+
92+
$filesInfo = array();
93+
foreach ($files as $file) {
94+
$filesInfo[] = $this->validate(file_get_contents($file), $file);
95+
}
96+
97+
return $this->display($input, $output, $filesInfo);
98+
}
99+
100+
private function validate($content, $file = null)
101+
{
102+
$this->parser = new Parser();
103+
try {
104+
$this->parser->parse($content);
105+
} catch (ParseException $e) {
106+
return array('file' => $file, 'valid' => false, 'message' => $e->getMessage());
107+
}
108+
109+
return array('file' => $file, 'valid' => true);
110+
}
111+
112+
private function display(InputInterface $input, OutputInterface $output, $files)
113+
{
114+
switch ($input->getOption('format')) {
115+
case 'txt':
116+
return $this->displayTxt($output, $files);
117+
case 'json':
118+
return $this->displayJson($output, $files);
119+
default:
120+
throw new \InvalidArgumentException(sprintf('The format "%s" is not supported.', $input->getOption('format')));
121+
}
122+
}
123+
124+
private function displayTxt(OutputInterface $output, $filesInfo)
125+
{
126+
$errors = 0;
127+
128+
foreach ($filesInfo as $info) {
129+
if ($info['valid'] && $output->isVerbose()) {
130+
$output->writeln('<info>OK</info>'.($info['file'] ? sprintf(' in %s', $info['file']) : ''));
131+
} elseif (!$info['valid']) {
132+
$errors++;
133+
$output->writeln(sprintf('<error>KO</error> in %s', $info['file']));
134+
$output->writeln(sprintf('<error>>> %s</error>', $info['message']));
135+
}
136+
}
137+
138+
$output->writeln(sprintf('<comment>%d/%d valid files</comment>', count($filesInfo) - $errors, count($filesInfo)));
139+
140+
return min($errors, 1);
141+
}
142+
143+
private function displayJson(OutputInterface $output, $filesInfo)
144+
{
145+
$errors = 0;
146+
147+
array_walk($filesInfo, function (&$v) use (&$errors) {
148+
$v['file'] = (string) $v['file'];
149+
if (!$v['valid']) {
150+
$errors++;
151+
}
152+
});
153+
154+
$output->writeln(json_encode($filesInfo));
155+
156+
return min($errors, 1);
157+
}
158+
}

0 commit comments

Comments
 (0)
0