Mercurial > hg > isophonics-drupal-site
comparison vendor/symfony/translation/Command/XliffLintCommand.php @ 14:1fec387a4317
Update Drupal core to 8.5.2 via Composer
author | Chris Cannam |
---|---|
date | Mon, 23 Apr 2018 09:46:53 +0100 |
parents | |
children | c2387f117808 |
comparison
equal
deleted
inserted
replaced
13:5fb285c0d0e3 | 14:1fec387a4317 |
---|---|
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\Translation\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\Console\Style\SymfonyStyle; | |
19 | |
20 /** | |
21 * Validates XLIFF files syntax and outputs encountered errors. | |
22 * | |
23 * @author Grégoire Pineau <lyrixx@lyrixx.info> | |
24 * @author Robin Chalas <robin.chalas@gmail.com> | |
25 * @author Javier Eguiluz <javier.eguiluz@gmail.com> | |
26 */ | |
27 class XliffLintCommand extends Command | |
28 { | |
29 protected static $defaultName = 'lint:xliff'; | |
30 | |
31 private $format; | |
32 private $displayCorrectFiles; | |
33 private $directoryIteratorProvider; | |
34 private $isReadableProvider; | |
35 | |
36 public function __construct($name = null, $directoryIteratorProvider = null, $isReadableProvider = null) | |
37 { | |
38 parent::__construct($name); | |
39 | |
40 $this->directoryIteratorProvider = $directoryIteratorProvider; | |
41 $this->isReadableProvider = $isReadableProvider; | |
42 } | |
43 | |
44 /** | |
45 * {@inheritdoc} | |
46 */ | |
47 protected function configure() | |
48 { | |
49 $this | |
50 ->setDescription('Lints a XLIFF file and outputs encountered errors') | |
51 ->addArgument('filename', null, 'A file or a directory or STDIN') | |
52 ->addOption('format', null, InputOption::VALUE_REQUIRED, 'The output format', 'txt') | |
53 ->setHelp(<<<EOF | |
54 The <info>%command.name%</info> command lints a XLIFF file and outputs to STDOUT | |
55 the first encountered syntax error. | |
56 | |
57 You can validates XLIFF contents passed from STDIN: | |
58 | |
59 <info>cat filename | php %command.full_name%</info> | |
60 | |
61 You can also validate the syntax of a file: | |
62 | |
63 <info>php %command.full_name% filename</info> | |
64 | |
65 Or of a whole directory: | |
66 | |
67 <info>php %command.full_name% dirname</info> | |
68 <info>php %command.full_name% dirname --format=json</info> | |
69 | |
70 EOF | |
71 ) | |
72 ; | |
73 } | |
74 | |
75 protected function execute(InputInterface $input, OutputInterface $output) | |
76 { | |
77 $io = new SymfonyStyle($input, $output); | |
78 $filename = $input->getArgument('filename'); | |
79 $this->format = $input->getOption('format'); | |
80 $this->displayCorrectFiles = $output->isVerbose(); | |
81 | |
82 if (!$filename) { | |
83 if (!$stdin = $this->getStdin()) { | |
84 throw new \RuntimeException('Please provide a filename or pipe file content to STDIN.'); | |
85 } | |
86 | |
87 return $this->display($io, array($this->validate($stdin))); | |
88 } | |
89 | |
90 if (!$this->isReadable($filename)) { | |
91 throw new \RuntimeException(sprintf('File or directory "%s" is not readable.', $filename)); | |
92 } | |
93 | |
94 $filesInfo = array(); | |
95 foreach ($this->getFiles($filename) as $file) { | |
96 $filesInfo[] = $this->validate(file_get_contents($file), $file); | |
97 } | |
98 | |
99 return $this->display($io, $filesInfo); | |
100 } | |
101 | |
102 private function validate($content, $file = null) | |
103 { | |
104 // Avoid: Warning DOMDocument::loadXML(): Empty string supplied as input | |
105 if ('' === trim($content)) { | |
106 return array('file' => $file, 'valid' => true); | |
107 } | |
108 | |
109 libxml_use_internal_errors(true); | |
110 | |
111 $document = new \DOMDocument(); | |
112 $document->loadXML($content); | |
113 if ($document->schemaValidate(__DIR__.'/../Resources/schemas/xliff-core-1.2-strict.xsd')) { | |
114 return array('file' => $file, 'valid' => true); | |
115 } | |
116 | |
117 $errorMessages = array_map(function ($error) { | |
118 return array( | |
119 'line' => $error->line, | |
120 'column' => $error->column, | |
121 'message' => trim($error->message), | |
122 ); | |
123 }, libxml_get_errors()); | |
124 | |
125 libxml_clear_errors(); | |
126 libxml_use_internal_errors(false); | |
127 | |
128 return array('file' => $file, 'valid' => false, 'messages' => $errorMessages); | |
129 } | |
130 | |
131 private function display(SymfonyStyle $io, array $files) | |
132 { | |
133 switch ($this->format) { | |
134 case 'txt': | |
135 return $this->displayTxt($io, $files); | |
136 case 'json': | |
137 return $this->displayJson($io, $files); | |
138 default: | |
139 throw new \InvalidArgumentException(sprintf('The format "%s" is not supported.', $this->format)); | |
140 } | |
141 } | |
142 | |
143 private function displayTxt(SymfonyStyle $io, array $filesInfo) | |
144 { | |
145 $countFiles = count($filesInfo); | |
146 $erroredFiles = 0; | |
147 | |
148 foreach ($filesInfo as $info) { | |
149 if ($info['valid'] && $this->displayCorrectFiles) { | |
150 $io->comment('<info>OK</info>'.($info['file'] ? sprintf(' in %s', $info['file']) : '')); | |
151 } elseif (!$info['valid']) { | |
152 ++$erroredFiles; | |
153 $io->text('<error> ERROR </error>'.($info['file'] ? sprintf(' in %s', $info['file']) : '')); | |
154 $io->listing(array_map(function ($error) { | |
155 // general document errors have a '-1' line number | |
156 return -1 === $error['line'] ? $error['message'] : sprintf('Line %d, Column %d: %s', $error['line'], $error['column'], $error['message']); | |
157 }, $info['messages'])); | |
158 } | |
159 } | |
160 | |
161 if (0 === $erroredFiles) { | |
162 $io->success(sprintf('All %d XLIFF files contain valid syntax.', $countFiles)); | |
163 } else { | |
164 $io->warning(sprintf('%d XLIFF files have valid syntax and %d contain errors.', $countFiles - $erroredFiles, $erroredFiles)); | |
165 } | |
166 | |
167 return min($erroredFiles, 1); | |
168 } | |
169 | |
170 private function displayJson(SymfonyStyle $io, array $filesInfo) | |
171 { | |
172 $errors = 0; | |
173 | |
174 array_walk($filesInfo, function (&$v) use (&$errors) { | |
175 $v['file'] = (string) $v['file']; | |
176 if (!$v['valid']) { | |
177 ++$errors; | |
178 } | |
179 }); | |
180 | |
181 $io->writeln(json_encode($filesInfo, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES)); | |
182 | |
183 return min($errors, 1); | |
184 } | |
185 | |
186 private function getFiles($fileOrDirectory) | |
187 { | |
188 if (is_file($fileOrDirectory)) { | |
189 yield new \SplFileInfo($fileOrDirectory); | |
190 | |
191 return; | |
192 } | |
193 | |
194 foreach ($this->getDirectoryIterator($fileOrDirectory) as $file) { | |
195 if (!in_array($file->getExtension(), array('xlf', 'xliff'))) { | |
196 continue; | |
197 } | |
198 | |
199 yield $file; | |
200 } | |
201 } | |
202 | |
203 private function getStdin() | |
204 { | |
205 if (0 !== ftell(STDIN)) { | |
206 return; | |
207 } | |
208 | |
209 $inputs = ''; | |
210 while (!feof(STDIN)) { | |
211 $inputs .= fread(STDIN, 1024); | |
212 } | |
213 | |
214 return $inputs; | |
215 } | |
216 | |
217 private function getDirectoryIterator($directory) | |
218 { | |
219 $default = function ($directory) { | |
220 return new \RecursiveIteratorIterator( | |
221 new \RecursiveDirectoryIterator($directory, \FilesystemIterator::SKIP_DOTS | \FilesystemIterator::FOLLOW_SYMLINKS), | |
222 \RecursiveIteratorIterator::LEAVES_ONLY | |
223 ); | |
224 }; | |
225 | |
226 if (null !== $this->directoryIteratorProvider) { | |
227 return call_user_func($this->directoryIteratorProvider, $directory, $default); | |
228 } | |
229 | |
230 return $default($directory); | |
231 } | |
232 | |
233 private function isReadable($fileOrDirectory) | |
234 { | |
235 $default = function ($fileOrDirectory) { | |
236 return is_readable($fileOrDirectory); | |
237 }; | |
238 | |
239 if (null !== $this->isReadableProvider) { | |
240 return call_user_func($this->isReadableProvider, $fileOrDirectory, $default); | |
241 } | |
242 | |
243 return $default($fileOrDirectory); | |
244 } | |
245 } |