* * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Behat\Testwork\Output\Cli; use Behat\Testwork\Cli\Controller; use Behat\Testwork\Output\Formatter; use Behat\Testwork\Output\OutputManager; use Symfony\Component\Console\Command\Command; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Input\InputOption; use Symfony\Component\Console\Output\OutputInterface; /** * Configures formatters based on user input. * * @author Konstantin Kudryashov */ class OutputController implements Controller { /** * @var OutputManager */ private $manager; /** * Initializes controller. * * @param OutputManager $manager */ public function __construct(OutputManager $manager) { $this->manager = $manager; } /** * {@inheritdoc} */ public function configure(Command $command) { $command ->addOption( '--format', '-f', InputOption::VALUE_REQUIRED | InputOption::VALUE_IS_ARRAY, 'How to format tests output. pretty is default.' . PHP_EOL . 'Available formats are:' . PHP_EOL . $this->getFormatterDescriptions() . 'You can use multiple formats at the same time.' ) ->addOption( '--out', '-o', InputOption::VALUE_REQUIRED | InputOption::VALUE_IS_ARRAY, 'Write format output to a file/directory instead of' . PHP_EOL . 'STDOUT (output_path). You can also provide different' . PHP_EOL . 'outputs to multiple formats.' ) ->addOption( '--format-settings', null, InputOption::VALUE_REQUIRED | InputOption::VALUE_IS_ARRAY, 'Set formatters parameters using json object.' . PHP_EOL . 'Keys are parameter names, values are values.' ); } /** * {@inheritdoc} */ public function execute(InputInterface $input, OutputInterface $output) { $formats = $input->getOption('format'); $outputs = $input->getOption('out'); $this->configureFormatters($formats, $input, $output); $this->configureOutputs($formats, $outputs, $output->isDecorated()); } /** * Configures formatters based on container, input and output configurations. * * @param array $formats * @param InputInterface $input * @param OutputInterface $output */ protected function configureFormatters(array $formats, InputInterface $input, OutputInterface $output) { $this->enableFormatters($formats); $this->setFormattersParameters($input, $output); } /** * Enables formatters. * * @param array $formats */ protected function enableFormatters(array $formats) { if (count($formats)) { $this->manager->disableAllFormatters(); foreach ($formats as $format) { $this->manager->enableFormatter($format); } } } /** * Sets formatters parameters based on input & output. * * @param InputInterface $input * @param OutputInterface $output */ protected function setFormattersParameters(InputInterface $input, OutputInterface $output) { $this->manager->setFormattersParameter('output_decorate', $output->isDecorated()); if ($input->getOption('format-settings')) { foreach ($input->getOption('format-settings') as $jsonSettings) { $this->loadJsonSettings($jsonSettings); } } } /** * Locates output path from relative one. * * @param string $path * * @return string */ protected function locateOutputPath($path) { if ($this->isAbsolutePath($path)) { return $path; } $path = getcwd() . DIRECTORY_SEPARATOR . $path; if (!file_exists($path)) { touch($path); $path = realpath($path); unlink($path); } else { $path = realpath($path); } return $path; } /** * Initializes multiple formatters with different outputs. * * @param array $formats * @param array $outputs * @param Boolean $decorated */ private function configureOutputs(array $formats, array $outputs, $decorated = false) { if (1 == count($outputs) && !$this->isStandardOutput($outputs[0])) { $outputPath = $this->locateOutputPath($outputs[0]); $this->manager->setFormattersParameter('output_path', $outputPath); $this->manager->setFormattersParameter('output_decorate', $decorated); return; } foreach ($outputs as $i => $out) { if ($this->isStandardOutput($out)) { continue; } $outputPath = $this->locateOutputPath($out); if (isset($formats[$i])) { $this->manager->setFormatterParameter($formats[$i], 'output_path', $outputPath); $this->manager->setFormatterParameter($formats[$i], 'output_decorate', $decorated); } } } /** * Checks if provided output identifier represents standard output. * * @param string $outputId * * @return Boolean */ private function isStandardOutput($outputId) { return 'std' === $outputId || 'null' === $outputId || 'false' === $outputId; } /** * Returns whether the file path is an absolute path. * * @param string $file A file path * * @return Boolean */ private function isAbsolutePath($file) { if ($file[0] == '/' || $file[0] == '\\' || (strlen($file) > 3 && ctype_alpha($file[0]) && $file[1] == ':' && ($file[2] == '\\' || $file[2] == '/') ) || null !== parse_url($file, PHP_URL_SCHEME) ) { return true; } return false; } /** * Returns formatters description. * * @return string */ private function getFormatterDescriptions() { return implode( PHP_EOL, array_map( function (Formatter $formatter) { $comment = '- ' . $formatter->getName() . ': '; $comment .= $formatter->getDescription(); return $comment; }, $this->manager->getFormatters() ) ) . PHP_EOL; } /** * Loads JSON settings as formatter parameters. * * @param string $jsonSettings */ private function loadJsonSettings($jsonSettings) { $settings = @json_decode($jsonSettings, true); if (!is_array($settings)) { return; } foreach ($settings as $name => $value) { $this->manager->setFormattersParameter($name, $value); } } }