bug #27143 [Console] By default hide the short exception trace line from 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 https://github.com/symfony/symfony/pull/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
-------

11f3c455d4 Hide short exception trace by default
This commit is contained in:
Nicolas Grekas 2018-05-04 10:44:42 -07:00
commit 278f40f48d
17 changed files with 49 additions and 28 deletions

View File

@ -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 @@ EOF
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 @@ EOF
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 @@ EOF
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')));
}
}

View File

@ -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 @@ abstract class AbstractConfigCommand extends ContainerDebugCommand
$message .= sprintf("\n\nDid you mean \"%s\"?", $guess);
}
throw new \LogicException($message);
throw new LogicException($message);
}
public function validateConfiguration(ExtensionInterface $extension, $configuration)

View File

@ -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 @@ EOT
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')));
}
}
}

View File

@ -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 @@ EOF
$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)));

View File

@ -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 @@ EOF
} 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));
}
}
}

View File

@ -13,6 +13,7 @@ namespace Symfony\Bundle\FrameworkBundle\Command;
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 @@ EOF
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));

View File

@ -13,6 +13,7 @@ namespace Symfony\Bundle\FrameworkBundle\Command;
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 @@ EOF
$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 @@ EOF
$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;

View File

@ -13,6 +13,7 @@ namespace Symfony\Bundle\FrameworkBundle\Command;
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 @@ EOF
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);

View File

@ -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 @@ EOF
$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')) {

View File

@ -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 @@ EOF
$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]));
}
}
}

View File

@ -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 @@ EOF
$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();

View File

@ -14,6 +14,7 @@ namespace Symfony\Bundle\SecurityBundle\Command;
@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 @@ EOF
$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 @@ EOF
$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], '/', '\\'));

View File

@ -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 @@ EOF
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 @@ EOF
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)) {

View File

@ -15,6 +15,8 @@ use Monolog\Formatter\FormatterInterface;
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 @@ EOF
$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 @@ EOF
}
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) {

View File

@ -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 @@ EOF
} 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;

View File

@ -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 @@ EOF
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 @@ EOF
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));
}
}

View File

@ -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 @@ EOF
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 @@ EOF
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));
}
}