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