Permalink
Browse files

bug #27143 [Console] By default hide the short exception trace line f…

…rom exception messages in Symfony's commands (yceruto)

This PR was merged into the 3.4 branch.

Discussion
----------

[Console] By default hide the short exception trace line from exception messages in Symfony's commands

| Q             | A
| ------------- | ---
| Branch?       | 3.4
| Bug fix?      | yes
| New feature?  | no
| BC breaks?    | no
| Deprecations? | no
| Tests pass?   | yes
| Fixed tickets | -
| License        | MIT
| Doc PR        | -

After #24131 this was in my contribution list since then.

Maybe it should be taken as a good practice when we build console commands, **use the exception classes of the Console component as much as possible to show a better message style to the end user**.

(See the before/after effect in the referenced PR)

Commits
-------

11f3c45 Hide short exception trace by default
  • Loading branch information...
nicolas-grekas committed May 4, 2018
2 parents 7bbadf5 + 11f3c45 commit 278f40f48d3eaa9f963000e238e94ae4554a62ba
@@ -12,6 +12,8 @@
namespace Symfony\Bridge\Twig\Command;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Exception\InvalidArgumentException;
use Symfony\Component\Console\Exception\RuntimeException;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
@@ -119,7 +121,7 @@ protected function execute(InputInterface $input, OutputInterface $output)
if (0 === count($filenames)) {
if (0 !== ftell(STDIN)) {
throw new \RuntimeException('Please provide a filename or pipe template content to STDIN.');
throw new RuntimeException('Please provide a filename or pipe template content to STDIN.');
}
$template = '';
@@ -155,7 +157,7 @@ protected function findFiles($filename)
return Finder::create()->files()->in($filename)->name('*.twig');
}
throw new \RuntimeException(sprintf('File or directory "%s" is not readable', $filename));
throw new RuntimeException(sprintf('File or directory "%s" is not readable', $filename));
}
private function validate($template, $file)
@@ -184,7 +186,7 @@ private function display(InputInterface $input, OutputInterface $output, Symfony
case 'json':
return $this->displayJson($output, $files);
default:
throw new \InvalidArgumentException(sprintf('The format "%s" is not supported.', $input->getOption('format')));
throw new InvalidArgumentException(sprintf('The format "%s" is not supported.', $input->getOption('format')));
}
}
@@ -12,6 +12,7 @@
namespace Symfony\Bundle\FrameworkBundle\Command;
use Symfony\Component\Config\Definition\ConfigurationInterface;
use Symfony\Component\Console\Exception\LogicException;
use Symfony\Component\Console\Helper\Table;
use Symfony\Component\Console\Style\StyleInterface;
use Symfony\Component\DependencyInjection\Extension\ExtensionInterface;
@@ -98,7 +99,7 @@ protected function findExtension($name)
$message .= sprintf("\n\nDid you mean \"%s\"?", $guess);
}
throw new \LogicException($message);
throw new LogicException($message);
}
public function validateConfiguration(ExtensionInterface $extension, $configuration)
@@ -11,6 +11,7 @@
namespace Symfony\Bundle\FrameworkBundle\Command;
use Symfony\Component\Console\Exception\InvalidArgumentException;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
@@ -115,7 +116,7 @@ protected function execute(InputInterface $input, OutputInterface $output)
if (is_dir(dirname($targetArg).'/web')) {
$targetArg = dirname($targetArg).'/web';
} else {
throw new \InvalidArgumentException(sprintf('The target directory "%s" does not exist.', $input->getArgument('target')));
throw new InvalidArgumentException(sprintf('The target directory "%s" does not exist.', $input->getArgument('target')));
}
}
}
@@ -11,6 +11,7 @@
namespace Symfony\Bundle\FrameworkBundle\Command;
use Symfony\Component\Console\Exception\RuntimeException;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;
@@ -104,7 +105,7 @@ protected function execute(InputInterface $input, OutputInterface $output)
$fs->remove($oldCacheDir);
if (!is_writable($realCacheDir)) {
throw new \RuntimeException(sprintf('Unable to write in the "%s" directory', $realCacheDir));
throw new RuntimeException(sprintf('Unable to write in the "%s" directory', $realCacheDir));
}
$io->comment(sprintf('Clearing the cache for the <info>%s</info> environment with debug <info>%s</info>', $kernel->getEnvironment(), var_export($kernel->isDebug(), true)));
@@ -12,6 +12,7 @@
namespace Symfony\Bundle\FrameworkBundle\Command;
use Psr\Cache\CacheItemPoolInterface;
use Symfony\Component\Console\Exception\InvalidArgumentException;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Output\OutputInterface;
@@ -93,7 +94,7 @@ protected function execute(InputInterface $input, OutputInterface $output)
} elseif ($pool instanceof Psr6CacheClearer) {
$clearers[$id] = $pool;
} else {
throw new \InvalidArgumentException(sprintf('"%s" is not a cache pool nor a cache clearer.', $id));
throw new InvalidArgumentException(sprintf('"%s" is not a cache pool nor a cache clearer.', $id));
}
}
}
@@ -13,6 +13,7 @@
use Symfony\Component\Config\Definition\Dumper\YamlReferenceDumper;
use Symfony\Component\Config\Definition\Dumper\XmlReferenceDumper;
use Symfony\Component\Console\Exception\InvalidArgumentException;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Input\InputInterface;
@@ -124,7 +125,7 @@ protected function execute(InputInterface $input, OutputInterface $output)
break;
default:
$io->writeln($message);
throw new \InvalidArgumentException('Only the yaml and xml formats are supported.');
throw new InvalidArgumentException('Only the yaml and xml formats are supported.');
}
$io->writeln(null === $path ? $dumper->dump($configuration, $extension->getNamespace()) : $dumper->dumpAtPath($configuration, $path));
@@ -13,6 +13,7 @@
use Symfony\Bundle\FrameworkBundle\Console\Helper\DescriptorHelper;
use Symfony\Component\Config\ConfigCache;
use Symfony\Component\Console\Exception\InvalidArgumentException;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Input\InputInterface;
@@ -167,9 +168,9 @@ protected function validateInput(InputInterface $input)
$name = $input->getArgument('name');
if ((null !== $name) && ($optionsCount > 0)) {
throw new \InvalidArgumentException('The options tags, tag, parameters & parameter can not be combined with the service name argument.');
throw new InvalidArgumentException('The options tags, tag, parameters & parameter can not be combined with the service name argument.');
} elseif ((null === $name) && $optionsCount > 1) {
throw new \InvalidArgumentException('The options tags, tag, parameters & parameter can not be combined together.');
throw new InvalidArgumentException('The options tags, tag, parameters & parameter can not be combined together.');
}
}
@@ -208,7 +209,7 @@ private function findProperServiceName(InputInterface $input, SymfonyStyle $io,
$matchingServices = $this->findServiceIdsContaining($builder, $name);
if (empty($matchingServices)) {
throw new \InvalidArgumentException(sprintf('No services found that match "%s".', $name));
throw new InvalidArgumentException(sprintf('No services found that match "%s".', $name));
}
$default = 1 === count($matchingServices) ? $matchingServices[0] : null;
@@ -13,6 +13,7 @@
use Symfony\Bundle\FrameworkBundle\Console\Helper\DescriptorHelper;
use Symfony\Bundle\FrameworkBundle\Controller\ControllerNameParser;
use Symfony\Component\Console\Exception\InvalidArgumentException;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
@@ -116,7 +117,7 @@ protected function execute(InputInterface $input, OutputInterface $output)
if ($name) {
if (!$route = $routes->get($name)) {
throw new \InvalidArgumentException(sprintf('The route "%s" does not exist.', $name));
throw new InvalidArgumentException(sprintf('The route "%s" does not exist.', $name));
}
$callable = $this->extractCallable($route);
@@ -11,6 +11,7 @@
namespace Symfony\Bundle\FrameworkBundle\Command;
use Symfony\Component\Console\Exception\InvalidArgumentException;
use Symfony\Component\Console\Style\SymfonyStyle;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputArgument;
@@ -182,7 +183,7 @@ protected function execute(InputInterface $input, OutputInterface $output)
$viewsPaths = array($input->getArgument('bundle').'/Resources/views');
if (!is_dir($transPaths[0])) {
throw new \InvalidArgumentException(sprintf('"%s" is neither an enabled bundle nor a directory.', $transPaths[0]));
throw new InvalidArgumentException(sprintf('"%s" is neither an enabled bundle nor a directory.', $transPaths[0]));
}
}
} elseif ($input->getOption('all')) {
@@ -11,6 +11,7 @@
namespace Symfony\Bundle\FrameworkBundle\Command;
use Symfony\Component\Console\Exception\InvalidArgumentException;
use Symfony\Component\Console\Style\SymfonyStyle;
use Symfony\Component\HttpKernel\KernelInterface;
use Symfony\Component\Translation\Catalogue\TargetOperation;
@@ -192,7 +193,7 @@ protected function execute(InputInterface $input, OutputInterface $output)
$currentName = $transPaths[0];
if (!is_dir($transPaths[0])) {
throw new \InvalidArgumentException(sprintf('<error>"%s" is neither an enabled bundle nor a directory.</error>', $transPaths[0]));
throw new InvalidArgumentException(sprintf('<error>"%s" is neither an enabled bundle nor a directory.</error>', $transPaths[0]));
}
}
}
@@ -11,6 +11,7 @@
namespace Symfony\Bundle\FrameworkBundle\Command;
use Symfony\Component\Console\Exception\InvalidArgumentException;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
@@ -63,7 +64,7 @@ protected function execute(InputInterface $input, OutputInterface $output)
$workflow = $container->get('state_machine.'.$serviceId);
$dumper = new StateMachineGraphvizDumper();
} else {
throw new \InvalidArgumentException(sprintf('No service found for "workflow.%1$s" nor "state_machine.%1$s".', $serviceId));
throw new InvalidArgumentException(sprintf('No service found for "workflow.%1$s" nor "state_machine.%1$s".', $serviceId));
}
$marking = new Marking();
@@ -14,6 +14,7 @@
@trigger_error(sprintf('Class "%s" is deprecated since Symfony 3.4 and will be removed in 4.0. Use Symfony\Bundle\AclBundle\Command\SetAclCommand instead.', SetAclCommand::class), E_USER_DEPRECATED);
use Symfony\Bundle\FrameworkBundle\Command\ContainerAwareCommand;
use Symfony\Component\Console\Exception\InvalidArgumentException;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
@@ -144,7 +145,7 @@ protected function execute(InputInterface $input, OutputInterface $output)
$classScopeOption = $input->getOption('class-scope');
if (empty($userOption) && empty($roleOption)) {
throw new \InvalidArgumentException('A Role or a User must be specified.');
throw new InvalidArgumentException('A Role or a User must be specified.');
}
// Create security identities
@@ -155,7 +156,7 @@ protected function execute(InputInterface $input, OutputInterface $output)
$data = explode(':', $user, 2);
if (1 === count($data)) {
throw new \InvalidArgumentException('The user must follow the format "Acme/MyUser:username".');
throw new InvalidArgumentException('The user must follow the format "Acme/MyUser:username".');
}
$securityIdentities[] = new UserSecurityIdentity($data[1], strtr($data[0], '/', '\\'));
@@ -12,6 +12,8 @@
namespace Symfony\Bundle\SecurityBundle\Command;
use Symfony\Bundle\FrameworkBundle\Command\ContainerAwareCommand;
use Symfony\Component\Console\Exception\InvalidArgumentException;
use Symfony\Component\Console\Exception\RuntimeException;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
@@ -179,7 +181,7 @@ private function createPasswordQuestion()
return $passwordQuestion->setValidator(function ($value) {
if ('' === trim($value)) {
throw new \Exception('The password must not be empty.');
throw new InvalidArgumentException('The password must not be empty.');
}
return $value;
@@ -203,7 +205,7 @@ private function getUserClass(InputInterface $input, SymfonyStyle $io)
return User::class;
}
throw new \RuntimeException('There are no configured encoders for the "security" extension.');
throw new RuntimeException('There are no configured encoders for the "security" extension.');
}
if (!$input->isInteractive() || 1 === count($this->userClasses)) {
@@ -15,6 +15,8 @@
use Symfony\Bridge\Monolog\Formatter\ConsoleFormatter;
use Symfony\Bridge\Monolog\Handler\ConsoleHandler;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Exception\LogicException;
use Symfony\Component\Console\Exception\RuntimeException;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;
@@ -78,7 +80,7 @@ protected function execute(InputInterface $input, OutputInterface $output)
$filter = $input->getOption('filter');
if ($filter) {
if (!class_exists(ExpressionLanguage::class)) {
throw new \LogicException('Package "symfony/expression-language" is required to use the "filter" option.');
throw new LogicException('Package "symfony/expression-language" is required to use the "filter" option.');
}
$this->el = new ExpressionLanguage();
}
@@ -97,7 +99,7 @@ protected function execute(InputInterface $input, OutputInterface $output)
}
if (!$socket = stream_socket_server($host, $errno, $errstr)) {
throw new \RuntimeException(sprintf('Server start failed on "%s": %s %s.', $host, $errstr, $errno));
throw new RuntimeException(sprintf('Server start failed on "%s": %s %s.', $host, $errstr, $errno));
}
foreach ($this->getLogs($socket) as $clientId => $message) {
@@ -12,6 +12,7 @@
namespace Symfony\Bundle\WebServerBundle\Command;
use Symfony\Bundle\WebServerBundle\WebServer;
use Symfony\Component\Console\Exception\InvalidArgumentException;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;
@@ -73,7 +74,7 @@ protected function execute(InputInterface $input, OutputInterface $output)
} elseif ('port' === $filter) {
$output->write($port);
} else {
throw new \InvalidArgumentException(sprintf('"%s" is not a valid filter.', $filter));
throw new InvalidArgumentException(sprintf('"%s" is not a valid filter.', $filter));
}
} else {
return 1;
@@ -12,6 +12,7 @@
namespace Symfony\Component\Translation\Command;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Exception\RuntimeException;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;
@@ -81,14 +82,14 @@ protected function execute(InputInterface $input, OutputInterface $output)
if (!$filename) {
if (!$stdin = $this->getStdin()) {
throw new \RuntimeException('Please provide a filename or pipe file content to STDIN.');
throw new RuntimeException('Please provide a filename or pipe file content to STDIN.');
}
return $this->display($io, array($this->validate($stdin)));
}
if (!$this->isReadable($filename)) {
throw new \RuntimeException(sprintf('File or directory "%s" is not readable.', $filename));
throw new RuntimeException(sprintf('File or directory "%s" is not readable.', $filename));
}
$filesInfo = array();
@@ -136,7 +137,7 @@ private function display(SymfonyStyle $io, array $files)
case 'json':
return $this->displayJson($io, $files);
default:
throw new \InvalidArgumentException(sprintf('The format "%s" is not supported.', $this->format));
throw new InvalidArgumentException(sprintf('The format "%s" is not supported.', $this->format));
}
}
@@ -12,6 +12,8 @@
namespace Symfony\Component\Yaml\Command;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Exception\InvalidArgumentException;
use Symfony\Component\Console\Exception\RuntimeException;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;
@@ -86,14 +88,14 @@ protected function execute(InputInterface $input, OutputInterface $output)
if (!$filename) {
if (!$stdin = $this->getStdin()) {
throw new \RuntimeException('Please provide a filename or pipe file content to STDIN.');
throw new RuntimeException('Please provide a filename or pipe file content to STDIN.');
}
return $this->display($io, array($this->validate($stdin, $flags)));
}
if (!$this->isReadable($filename)) {
throw new \RuntimeException(sprintf('File or directory "%s" is not readable.', $filename));
throw new RuntimeException(sprintf('File or directory "%s" is not readable.', $filename));
}
$filesInfo = array();
@@ -133,7 +135,7 @@ private function display(SymfonyStyle $io, array $files)
case 'json':
return $this->displayJson($io, $files);
default:
throw new \InvalidArgumentException(sprintf('The format "%s" is not supported.', $this->format));
throw new InvalidArgumentException(sprintf('The format "%s" is not supported.', $this->format));
}
}

0 comments on commit 278f40f

Please sign in to comment.