Skip to content

Navigation Menu

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

[Console] Support binary / negatable options #39642

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Jan 5, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 1 addition & 2 deletions 3 src/Symfony/Component/Console/Application.php
Original file line number Diff line number Diff line change
Expand Up @@ -1033,8 +1033,7 @@ protected function getDefaultInputDefinition()
new InputOption('--quiet', '-q', InputOption::VALUE_NONE, 'Do not output any message'),
new InputOption('--verbose', '-v|vv|vvv', InputOption::VALUE_NONE, 'Increase the verbosity of messages: 1 for normal output, 2 for more verbose output and 3 for debug'),
new InputOption('--version', '-V', InputOption::VALUE_NONE, 'Display this application version'),
new InputOption('--ansi', '', InputOption::VALUE_NONE, 'Force ANSI output'),
new InputOption('--no-ansi', '', InputOption::VALUE_NONE, 'Disable ANSI output'),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why was this flag removed?

new InputOption('--ansi', '', InputOption::VALUE_NEGATABLE, 'Force (or disable --no-ansi) ANSI output', null),
new InputOption('--no-interaction', '-n', InputOption::VALUE_NONE, 'Do not ask any interactive question'),
]);
}
Expand Down
1 change: 1 addition & 0 deletions 1 src/Symfony/Component/Console/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ CHANGELOG
-----

* Added `GithubActionReporter` to render annotations in a Github Action
* Added `InputOption::VALUE_NEGATABLE` flag to handle `--foo`/`--no-foo` options.

5.2.0
-----
Expand Down
18 changes: 16 additions & 2 deletions 18 src/Symfony/Component/Console/Descriptor/JsonDescriptor.php
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,9 @@ protected function describeInputArgument(InputArgument $argument, array $options
protected function describeInputOption(InputOption $option, array $options = [])
{
$this->writeData($this->getInputOptionData($option), $options);
if ($option->isNegatable()) {
$this->writeData($this->getInputOptionData($option, true), $options);
}
}

/**
Expand Down Expand Up @@ -111,9 +114,17 @@ private function getInputArgumentData(InputArgument $argument): array
];
}

private function getInputOptionData(InputOption $option): array
private function getInputOptionData(InputOption $option, bool $negated = false): array
{
return [
return $negated ? [
'name' => '--no-'.$option->getName(),
'shortcut' => '',
'accept_value' => false,
'is_value_required' => false,
'is_multiple' => false,
'description' => 'Negate the "--'.$option->getName().'" option',
'default' => false,
] : [
'name' => '--'.$option->getName(),
'shortcut' => $option->getShortcut() ? '-'.str_replace('|', '|-', $option->getShortcut()) : '',
'accept_value' => $option->acceptValue(),
Expand All @@ -134,6 +145,9 @@ private function getInputDefinitionData(InputDefinition $definition): array
$inputOptions = [];
foreach ($definition->getOptions() as $name => $option) {
$inputOptions[$name] = $this->getInputOptionData($option);
if ($option->isNegatable()) {
$inputOptions['no-'.$name] = $this->getInputOptionData($option, true);
}
}

return ['arguments' => $inputArguments, 'options' => $inputOptions];
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,9 @@ protected function describeInputArgument(InputArgument $argument, array $options
protected function describeInputOption(InputOption $option, array $options = [])
{
$name = '--'.$option->getName();
if ($option->isNegatable()) {
$name .= '|--no-'.$option->getName();
}
if ($option->getShortcut()) {
$name .= '|-'.str_replace('|', '|-', $option->getShortcut()).'';
}
Expand All @@ -79,6 +82,7 @@ protected function describeInputOption(InputOption $option, array $options = [])
.'* Accept value: '.($option->acceptValue() ? 'yes' : 'no')."\n"
.'* Is value required: '.($option->isValueRequired() ? 'yes' : 'no')."\n"
.'* Is multiple: '.($option->isArray() ? 'yes' : 'no')."\n"
.'* Is negatable: '.($option->isNegatable() ? 'yes' : 'no')."\n"
.'* Default: `'.str_replace("\n", '', var_export($option->getDefault(), true)).'`'
);
}
Expand Down
7 changes: 4 additions & 3 deletions 7 src/Symfony/Component/Console/Descriptor/TextDescriptor.php
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ protected function describeInputOption(InputOption $option, array $options = [])
$totalWidth = isset($options['total_width']) ? $options['total_width'] : $this->calculateTotalWidthForOptions([$option]);
$synopsis = sprintf('%s%s',
$option->getShortcut() ? sprintf('-%s, ', $option->getShortcut()) : ' ',
sprintf('--%s%s', $option->getName(), $value)
sprintf($option->isNegatable() ? '--%1$s|--no-%1$s' : '--%1$s%2$s', $option->getName(), $value)
);

$spacingWidth = $totalWidth - Helper::strlen($synopsis);
Expand Down Expand Up @@ -325,8 +325,9 @@ private function calculateTotalWidthForOptions(array $options): int
foreach ($options as $option) {
// "-" + shortcut + ", --" + name
$nameLength = 1 + max(Helper::strlen($option->getShortcut()), 1) + 4 + Helper::strlen($option->getName());

if ($option->acceptValue()) {
if ($option->isNegatable()) {
$nameLength += 6 + Helper::strlen($option->getName()); // |--no- + name
} elseif ($option->acceptValue()) {
$valueLength = 1 + Helper::strlen($option->getName()); // = + value
$valueLength += $option->isValueOptional() ? 2 : 0; // [ + ]

Expand Down
11 changes: 11 additions & 0 deletions 11 src/Symfony/Component/Console/Descriptor/XmlDescriptor.php
Original file line number Diff line number Diff line change
Expand Up @@ -225,6 +225,17 @@ private function getInputOptionDocument(InputOption $option): \DOMDocument
}
}

if ($option->isNegatable()) {
$dom->appendChild($objectXML = $dom->createElement('option'));
$objectXML->setAttribute('name', '--no-'.$option->getName());
$objectXML->setAttribute('shortcut', '');
$objectXML->setAttribute('accept_value', 0);
$objectXML->setAttribute('is_value_required', 0);
$objectXML->setAttribute('is_multiple', 0);
$objectXML->appendChild($descriptionXML = $dom->createElement('description'));
$descriptionXML->appendChild($dom->createTextNode('Negate the "--'.$option->getName().'" option'));
}

return $dom;
}
}
12 changes: 11 additions & 1 deletion 12 src/Symfony/Component/Console/Input/ArgvInput.php
Original file line number Diff line number Diff line change
Expand Up @@ -209,7 +209,17 @@ private function addShortOption(string $shortcut, $value)
private function addLongOption(string $name, $value)
{
if (!$this->definition->hasOption($name)) {
throw new RuntimeException(sprintf('The "--%s" option does not exist.', $name));
if (!$this->definition->hasNegation($name)) {
throw new RuntimeException(sprintf('The "--%s" option does not exist.', $name));
}

$optionName = $this->definition->negationToName($name);
if (null !== $value) {
throw new RuntimeException(sprintf('The "--%s" option does not accept a value.', $name));
}
$this->options[$optionName] = false;

return;
}

$option = $this->definition->getOption($name);
Expand Down
9 changes: 8 additions & 1 deletion 9 src/Symfony/Component/Console/Input/ArrayInput.php
Original file line number Diff line number Diff line change
Expand Up @@ -165,7 +165,14 @@ private function addShortOption(string $shortcut, $value)
private function addLongOption(string $name, $value)
{
if (!$this->definition->hasOption($name)) {
throw new InvalidOptionException(sprintf('The "--%s" option does not exist.', $name));
if (!$this->definition->hasNegation($name)) {
throw new InvalidOptionException(sprintf('The "--%s" option does not exist.', $name));
}

$optionName = $this->definition->negationToName($name);
$this->options[$optionName] = false;

return;
}

$option = $this->definition->getOption($name);
Expand Down
37 changes: 36 additions & 1 deletion 37 src/Symfony/Component/Console/Input/InputDefinition.php
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ class InputDefinition
private $hasAnArrayArgument = false;
private $hasOptional;
private $options;
private $negations;
private $shortcuts;

/**
Expand Down Expand Up @@ -208,6 +209,7 @@ public function setOptions(array $options = [])
{
$this->options = [];
$this->shortcuts = [];
$this->negations = [];
$this->addOptions($options);
}

Expand Down Expand Up @@ -246,6 +248,14 @@ public function addOption(InputOption $option)
$this->shortcuts[$shortcut] = $option->getName();
}
}

if ($option->isNegatable()) {
$negatedName = 'no-'.$option->getName();
if (isset($this->options[$negatedName])) {
throw new LogicException(sprintf('An option named "%s" already exists.', $negatedName));
jderusse marked this conversation as resolved.
Show resolved Hide resolved
}
$this->negations[$negatedName] = $option->getName();
}
}

/**
Expand Down Expand Up @@ -297,6 +307,14 @@ public function hasShortcut(string $name)
return isset($this->shortcuts[$name]);
}

/**
* Returns true if an InputOption object exists by negated name.
jderusse marked this conversation as resolved.
Show resolved Hide resolved
*/
public function hasNegation(string $name): bool
{
return isset($this->negations[$name]);
}

/**
* Gets an InputOption by shortcut.
*
Expand Down Expand Up @@ -338,6 +356,22 @@ public function shortcutToName(string $shortcut): string
return $this->shortcuts[$shortcut];
}

/**
* Returns the InputOption name given a negation.
*
* @throws InvalidArgumentException When option given does not exist
jderusse marked this conversation as resolved.
Show resolved Hide resolved
*
* @internal
*/
public function negationToName(string $negation): string
{
if (!isset($this->negations[$negation])) {
throw new InvalidArgumentException(sprintf('The "--%s" option does not exist.', $negation));
}

return $this->negations[$negation];
}

/**
* Gets the synopsis.
*
Expand All @@ -362,7 +396,8 @@ public function getSynopsis(bool $short = false)
}

$shortcut = $option->getShortcut() ? sprintf('-%s|', $option->getShortcut()) : '';
$elements[] = sprintf('[%s--%s%s]', $shortcut, $option->getName(), $value);
$negation = $option->isNegatable() ? sprintf('|--no-%s', $option->getName()) : '';
$elements[] = sprintf('[%s--%s%s%s]', $shortcut, $option->getName(), $value, $negation);
}
}

Expand Down
15 changes: 14 additions & 1 deletion 15 src/Symfony/Component/Console/Input/InputOption.php
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ class InputOption
public const VALUE_REQUIRED = 2;
public const VALUE_OPTIONAL = 4;
public const VALUE_IS_ARRAY = 8;
public const VALUE_NEGATABLE = 16;

private $name;
private $shortcut;
Expand Down Expand Up @@ -70,7 +71,7 @@ public function __construct(string $name, $shortcut = null, int $mode = null, st

if (null === $mode) {
$mode = self::VALUE_NONE;
} elseif ($mode > 15 || $mode < 1) {
} elseif ($mode >= (self::VALUE_NEGATABLE << 1) || $mode < 1) {
throw new InvalidArgumentException(sprintf('Option mode "%s" is not valid.', $mode));
}

Expand All @@ -82,6 +83,9 @@ public function __construct(string $name, $shortcut = null, int $mode = null, st
if ($this->isArray() && !$this->acceptValue()) {
throw new InvalidArgumentException('Impossible to have an option mode VALUE_IS_ARRAY if the option does not accept a value.');
}
if ($this->isNegatable() && $this->acceptValue()) {
throw new InvalidArgumentException('Impossible to have an option mode VALUE_NEGATABLE if the option also accepts a value.');
}

$this->setDefault($default);
}
Expand Down Expand Up @@ -146,6 +150,11 @@ public function isArray()
return self::VALUE_IS_ARRAY === (self::VALUE_IS_ARRAY & $this->mode);
}

public function isNegatable(): bool
{
return self::VALUE_NEGATABLE === (self::VALUE_NEGATABLE & $this->mode);
}

/**
* Sets the default value.
*
Expand All @@ -158,6 +167,9 @@ public function setDefault($default = null)
if (self::VALUE_NONE === (self::VALUE_NONE & $this->mode) && null !== $default) {
throw new LogicException('Cannot set a default value when using InputOption::VALUE_NONE mode.');
}
if (self::VALUE_NEGATABLE === (self::VALUE_NEGATABLE & $this->mode) && null !== $default) {
throw new LogicException('Cannot set a default value when using InputOption::VALUE_NEGATABLE mode.');
}

if ($this->isArray()) {
if (null === $default) {
Expand Down Expand Up @@ -200,6 +212,7 @@ public function equals(self $option)
return $option->getName() === $this->getName()
&& $option->getShortcut() === $this->getShortcut()
&& $option->getDefault() === $this->getDefault()
&& $option->isNegatable() === $this->isNegatable()
&& $option->isArray() === $this->isArray()
&& $option->isValueRequired() === $this->isValueRequired()
&& $option->isValueOptional() === $this->isValueOptional()
Expand Down
7 changes: 4 additions & 3 deletions 7 src/Symfony/Component/Console/Tests/ApplicationTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -1257,7 +1257,8 @@ public function testGetDefaultInputDefinitionReturnsDefaultValues()
$this->assertTrue($inputDefinition->hasOption('verbose'));
$this->assertTrue($inputDefinition->hasOption('version'));
$this->assertTrue($inputDefinition->hasOption('ansi'));
$this->assertTrue($inputDefinition->hasOption('no-ansi'));
$this->assertTrue($inputDefinition->hasNegation('no-ansi'));
$this->assertFalse($inputDefinition->hasOption('no-ansi'));
$this->assertTrue($inputDefinition->hasOption('no-interaction'));
}

Expand All @@ -1277,7 +1278,7 @@ public function testOverwritingDefaultInputDefinitionOverwritesDefaultValues()
$this->assertFalse($inputDefinition->hasOption('verbose'));
$this->assertFalse($inputDefinition->hasOption('version'));
$this->assertFalse($inputDefinition->hasOption('ansi'));
$this->assertFalse($inputDefinition->hasOption('no-ansi'));
$this->assertFalse($inputDefinition->hasNegation('no-ansi'));
$this->assertFalse($inputDefinition->hasOption('no-interaction'));

$this->assertTrue($inputDefinition->hasOption('custom'));
Expand All @@ -1301,7 +1302,7 @@ public function testSettingCustomInputDefinitionOverwritesDefaultValues()
$this->assertFalse($inputDefinition->hasOption('verbose'));
$this->assertFalse($inputDefinition->hasOption('version'));
$this->assertFalse($inputDefinition->hasOption('ansi'));
$this->assertFalse($inputDefinition->hasOption('no-ansi'));
$this->assertFalse($inputDefinition->hasNegation('no-ansi'));
$this->assertFalse($inputDefinition->hasOption('no-interaction'));

$this->assertTrue($inputDefinition->hasOption('custom'));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -80,8 +80,7 @@ public function testExecuteListsCommandsOrder()
-h, --help Display help for the given command. When no command is given display help for the list command
-q, --quiet Do not output any message
-V, --version Display this application version
--ansi Force ANSI output
--no-ansi Disable ANSI output
--ansi|--no-ansi Force (or disable --no-ansi) ANSI output
-n, --no-interaction Do not ask any interactive question
-v|vv|vvv, --verbose Increase the verbosity of messages: 1 for normal output, 2 for more verbose output and 3 for debug

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@
"accept_value": false,
"is_value_required": false,
"is_multiple": false,
"description": "Force ANSI output",
"description": "Force (or disable --no-ansi) ANSI output",
"default": false
},
"no-ansi": {
Expand All @@ -88,7 +88,7 @@
"accept_value": false,
"is_value_required": false,
"is_multiple": false,
"description": "Disable ANSI output",
"description": "Negate the \"--ansi\" option",
"default": false
},
"no-interaction": {
Expand Down Expand Up @@ -182,7 +182,7 @@
"accept_value": false,
"is_value_required": false,
"is_multiple": false,
"description": "Force ANSI output",
"description": "Force (or disable --no-ansi) ANSI output",
"default": false
},
"no-ansi": {
Expand All @@ -191,7 +191,7 @@
"accept_value": false,
"is_value_required": false,
"is_multiple": false,
"description": "Disable ANSI output",
"description": "Negate the \"--ansi\" option",
"default": false
},
"no-interaction": {
Expand Down
Loading
Morty Proxy This is a proxified and sanitized view of the page, visit original site.