Updating Media dependent modules to versions compatible with core Media.
[yaffs-website] / vendor / symfony / yaml / Command / LintCommand.php
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\Component\Yaml\Command;
13
14 use Symfony\Component\Console\Command\Command;
15 use Symfony\Component\Console\Exception\InvalidArgumentException;
16 use Symfony\Component\Console\Exception\RuntimeException;
17 use Symfony\Component\Console\Input\InputInterface;
18 use Symfony\Component\Console\Input\InputOption;
19 use Symfony\Component\Console\Output\OutputInterface;
20 use Symfony\Component\Console\Style\SymfonyStyle;
21 use Symfony\Component\Yaml\Exception\ParseException;
22 use Symfony\Component\Yaml\Parser;
23 use Symfony\Component\Yaml\Yaml;
24
25 /**
26  * Validates YAML files syntax and outputs encountered errors.
27  *
28  * @author GrĂ©goire Pineau <lyrixx@lyrixx.info>
29  * @author Robin Chalas <robin.chalas@gmail.com>
30  */
31 class LintCommand extends Command
32 {
33     protected static $defaultName = 'lint:yaml';
34
35     private $parser;
36     private $format;
37     private $displayCorrectFiles;
38     private $directoryIteratorProvider;
39     private $isReadableProvider;
40
41     public function __construct($name = null, $directoryIteratorProvider = null, $isReadableProvider = null)
42     {
43         parent::__construct($name);
44
45         $this->directoryIteratorProvider = $directoryIteratorProvider;
46         $this->isReadableProvider = $isReadableProvider;
47     }
48
49     /**
50      * {@inheritdoc}
51      */
52     protected function configure()
53     {
54         $this
55             ->setDescription('Lints a file and outputs encountered errors')
56             ->addArgument('filename', null, 'A file or a directory or STDIN')
57             ->addOption('format', null, InputOption::VALUE_REQUIRED, 'The output format', 'txt')
58             ->addOption('parse-tags', null, InputOption::VALUE_NONE, 'Parse custom tags')
59             ->setHelp(<<<EOF
60 The <info>%command.name%</info> command lints a YAML file and outputs to STDOUT
61 the first encountered syntax error.
62
63 You can validates YAML contents passed from STDIN:
64
65   <info>cat filename | php %command.full_name%</info>
66
67 You can also validate the syntax of a file:
68
69   <info>php %command.full_name% filename</info>
70
71 Or of a whole directory:
72
73   <info>php %command.full_name% dirname</info>
74   <info>php %command.full_name% dirname --format=json</info>
75
76 EOF
77             )
78         ;
79     }
80
81     protected function execute(InputInterface $input, OutputInterface $output)
82     {
83         $io = new SymfonyStyle($input, $output);
84         $filename = $input->getArgument('filename');
85         $this->format = $input->getOption('format');
86         $this->displayCorrectFiles = $output->isVerbose();
87         $flags = $input->getOption('parse-tags') ? Yaml::PARSE_CUSTOM_TAGS : 0;
88
89         if (!$filename) {
90             if (!$stdin = $this->getStdin()) {
91                 throw new RuntimeException('Please provide a filename or pipe file content to STDIN.');
92             }
93
94             return $this->display($io, array($this->validate($stdin, $flags)));
95         }
96
97         if (!$this->isReadable($filename)) {
98             throw new RuntimeException(sprintf('File or directory "%s" is not readable.', $filename));
99         }
100
101         $filesInfo = array();
102         foreach ($this->getFiles($filename) as $file) {
103             $filesInfo[] = $this->validate(file_get_contents($file), $flags, $file);
104         }
105
106         return $this->display($io, $filesInfo);
107     }
108
109     private function validate($content, $flags, $file = null)
110     {
111         $prevErrorHandler = set_error_handler(function ($level, $message, $file, $line) use (&$prevErrorHandler) {
112             if (E_USER_DEPRECATED === $level) {
113                 throw new ParseException($message, $this->getParser()->getRealCurrentLineNb() + 1);
114             }
115
116             return $prevErrorHandler ? $prevErrorHandler($level, $message, $file, $line) : false;
117         });
118
119         try {
120             $this->getParser()->parse($content, Yaml::PARSE_CONSTANT | $flags);
121         } catch (ParseException $e) {
122             return array('file' => $file, 'line' => $e->getParsedLine(), 'valid' => false, 'message' => $e->getMessage());
123         } finally {
124             restore_error_handler();
125         }
126
127         return array('file' => $file, 'valid' => true);
128     }
129
130     private function display(SymfonyStyle $io, array $files)
131     {
132         switch ($this->format) {
133             case 'txt':
134                 return $this->displayTxt($io, $files);
135             case 'json':
136                 return $this->displayJson($io, $files);
137             default:
138                 throw new InvalidArgumentException(sprintf('The format "%s" is not supported.', $this->format));
139         }
140     }
141
142     private function displayTxt(SymfonyStyle $io, array $filesInfo)
143     {
144         $countFiles = count($filesInfo);
145         $erroredFiles = 0;
146
147         foreach ($filesInfo as $info) {
148             if ($info['valid'] && $this->displayCorrectFiles) {
149                 $io->comment('<info>OK</info>'.($info['file'] ? sprintf(' in %s', $info['file']) : ''));
150             } elseif (!$info['valid']) {
151                 ++$erroredFiles;
152                 $io->text('<error> ERROR </error>'.($info['file'] ? sprintf(' in %s', $info['file']) : ''));
153                 $io->text(sprintf('<error> >> %s</error>', $info['message']));
154             }
155         }
156
157         if (0 === $erroredFiles) {
158             $io->success(sprintf('All %d YAML files contain valid syntax.', $countFiles));
159         } else {
160             $io->warning(sprintf('%d YAML files have valid syntax and %d contain errors.', $countFiles - $erroredFiles, $erroredFiles));
161         }
162
163         return min($erroredFiles, 1);
164     }
165
166     private function displayJson(SymfonyStyle $io, array $filesInfo)
167     {
168         $errors = 0;
169
170         array_walk($filesInfo, function (&$v) use (&$errors) {
171             $v['file'] = (string) $v['file'];
172             if (!$v['valid']) {
173                 ++$errors;
174             }
175         });
176
177         $io->writeln(json_encode($filesInfo, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES));
178
179         return min($errors, 1);
180     }
181
182     private function getFiles($fileOrDirectory)
183     {
184         if (is_file($fileOrDirectory)) {
185             yield new \SplFileInfo($fileOrDirectory);
186
187             return;
188         }
189
190         foreach ($this->getDirectoryIterator($fileOrDirectory) as $file) {
191             if (!in_array($file->getExtension(), array('yml', 'yaml'))) {
192                 continue;
193             }
194
195             yield $file;
196         }
197     }
198
199     private function getStdin()
200     {
201         if (0 !== ftell(STDIN)) {
202             return;
203         }
204
205         $inputs = '';
206         while (!feof(STDIN)) {
207             $inputs .= fread(STDIN, 1024);
208         }
209
210         return $inputs;
211     }
212
213     private function getParser()
214     {
215         if (!$this->parser) {
216             $this->parser = new Parser();
217         }
218
219         return $this->parser;
220     }
221
222     private function getDirectoryIterator($directory)
223     {
224         $default = function ($directory) {
225             return new \RecursiveIteratorIterator(
226                 new \RecursiveDirectoryIterator($directory, \FilesystemIterator::SKIP_DOTS | \FilesystemIterator::FOLLOW_SYMLINKS),
227                 \RecursiveIteratorIterator::LEAVES_ONLY
228             );
229         };
230
231         if (null !== $this->directoryIteratorProvider) {
232             return call_user_func($this->directoryIteratorProvider, $directory, $default);
233         }
234
235         return $default($directory);
236     }
237
238     private function isReadable($fileOrDirectory)
239     {
240         $default = function ($fileOrDirectory) {
241             return is_readable($fileOrDirectory);
242         };
243
244         if (null !== $this->isReadableProvider) {
245             return call_user_func($this->isReadableProvider, $fileOrDirectory, $default);
246         }
247
248         return $default($fileOrDirectory);
249     }
250 }