Merge pull request #18444 from owncloud/occ-config-types

occ config:system:set can now set other value types
This commit is contained in:
Thomas Müller 2016-01-25 10:02:51 +01:00
commit ce753231eb
6 changed files with 414 additions and 74 deletions

View File

@ -48,8 +48,8 @@ class DeleteConfig extends Base {
->setDescription('Delete a system config value')
->addArgument(
'name',
InputArgument::REQUIRED,
'Name of the config to delete'
InputArgument::REQUIRED | InputArgument::IS_ARRAY,
'Name of the config to delete, specify multiple for array parameter'
)
->addOption(
'error-if-not-exists',
@ -61,15 +61,57 @@ class DeleteConfig extends Base {
}
protected function execute(InputInterface $input, OutputInterface $output) {
$configName = $input->getArgument('name');
$configNames = $input->getArgument('name');
$configName = $configNames[0];
if ($input->hasParameterOption('--error-if-not-exists') && !in_array($configName, $this->systemConfig->getKeys())) {
$output->writeln('<error>System config ' . $configName . ' could not be deleted because it did not exist</error>');
return 1;
if (sizeof($configNames) > 1) {
if ($input->hasParameterOption('--error-if-not-exists') && !in_array($configName, $this->systemConfig->getKeys())) {
$output->writeln('<error>System config ' . implode(' => ', $configNames) . ' could not be deleted because it did not exist</error>');
return 1;
}
$value = $this->systemConfig->getValue($configName);
try {
$value = $this->removeSubValue(array_slice($configNames, 1), $value, $input->hasParameterOption('--error-if-not-exists'));
}
catch (\UnexpectedValueException $e) {
$output->writeln('<error>System config ' . implode(' => ', $configNames) . ' could not be deleted because it did not exist</error>');
return 1;
}
$this->systemConfig->setValue($configName, $value);
$output->writeln('<info>System config value ' . implode(' => ', $configNames) . ' deleted</info>');
return 0;
} else {
if ($input->hasParameterOption('--error-if-not-exists') && !in_array($configName, $this->systemConfig->getKeys())) {
$output->writeln('<error>System config ' . $configName . ' could not be deleted because it did not exist</error>');
return 1;
}
$this->systemConfig->deleteValue($configName);
$output->writeln('<info>System config value ' . $configName . ' deleted</info>');
return 0;
}
}
protected function removeSubValue($keys, $currentValue, $throwError) {
$nextKey = array_shift($keys);
if (is_array($currentValue)) {
if (isset($currentValue[$nextKey])) {
if (empty($keys)) {
unset($currentValue[$nextKey]);
} else {
$currentValue[$nextKey] = $this->removeSubValue($keys, $currentValue[$nextKey], $throwError);
}
} else if ($throwError) {
throw new \UnexpectedValueException('Config parameter does not exist');
}
} else if ($throwError) {
throw new \UnexpectedValueException('Config parameter does not exist');
}
$this->systemConfig->deleteValue($configName);
$output->writeln('<info>System config value ' . $configName . ' deleted</info>');
return 0;
return $currentValue;
}
}

View File

@ -48,8 +48,8 @@ class GetConfig extends Base {
->setDescription('Get a system config value')
->addArgument(
'name',
InputArgument::REQUIRED,
'Name of the config to get'
InputArgument::REQUIRED | InputArgument::IS_ARRAY,
'Name of the config to get, specify multiple for array parameter'
)
->addOption(
'default-value',
@ -68,7 +68,8 @@ class GetConfig extends Base {
* @return null|int null or 0 if everything went fine, or an error code
*/
protected function execute(InputInterface $input, OutputInterface $output) {
$configName = $input->getArgument('name');
$configNames = $input->getArgument('name');
$configName = array_shift($configNames);
$defaultValue = $input->getOption('default-value');
if (!in_array($configName, $this->systemConfig->getKeys()) && !$input->hasParameterOption('--default-value')) {
@ -79,6 +80,18 @@ class GetConfig extends Base {
$configValue = $defaultValue;
} else {
$configValue = $this->systemConfig->getValue($configName);
if (!empty($configNames)) {
foreach ($configNames as $configName) {
if (isset($configValue[$configName])) {
$configValue = $configValue[$configName];
} else if (!$input->hasParameterOption('--default-value')) {
return 1;
} else {
$configValue = $defaultValue;
break;
}
}
}
}
$this->writeMixedInOutputFormat($input, $output, $configValue);

View File

@ -48,8 +48,15 @@ class SetConfig extends Base {
->setDescription('Set a system config value')
->addArgument(
'name',
InputArgument::REQUIRED,
'Name of the config to set'
InputArgument::REQUIRED | InputArgument::IS_ARRAY,
'Name of the config parameter, specify multiple for array parameter'
)
->addOption(
'type',
null,
InputOption::VALUE_REQUIRED,
'Value type [string, integer, double, boolean]',
'string'
)
->addOption(
'value',
@ -67,16 +74,124 @@ class SetConfig extends Base {
}
protected function execute(InputInterface $input, OutputInterface $output) {
$configName = $input->getArgument('name');
$configNames = $input->getArgument('name');
$configName = $configNames[0];
$configValue = $this->castValue($input->getOption('value'), $input->getOption('type'));
$updateOnly = $input->getOption('update-only');
if (!in_array($configName, $this->systemConfig->getKeys()) && $input->hasParameterOption('--update-only')) {
$output->writeln('<comment>Config value ' . $configName . ' not updated, as it has not been set before.</comment>');
return 1;
if (sizeof($configNames) > 1) {
$existingValue = $this->systemConfig->getValue($configName);
$newValue = $this->mergeArrayValue(
array_slice($configNames, 1), $existingValue, $configValue['value'], $updateOnly
);
$this->systemConfig->setValue($configName, $newValue);
} else {
if ($updateOnly && !in_array($configName, $this->systemConfig->getKeys(), true)) {
throw new \UnexpectedValueException('Config parameter does not exist');
}
$this->systemConfig->setValue($configName, $configValue['value']);
}
$configValue = $input->getOption('value');
$this->systemConfig->setValue($configName, $configValue);
$output->writeln('<info>System config value ' . $configName . ' set to ' . $configValue . '</info>');
$output->writeln('<info>System config value ' . implode(' => ', $configNames) . ' set to ' . $configValue['readable-value'] . '</info>');
return 0;
}
/**
* @param string $value
* @param string $type
* @return mixed
* @throws \InvalidArgumentException
*/
protected function castValue($value, $type) {
switch ($type) {
case 'integer':
case 'int':
if (!is_numeric($value)) {
throw new \InvalidArgumentException('Non-numeric value specified');
}
return [
'value' => (int) $value,
'readable-value' => 'integer ' . (int) $value,
];
case 'double':
case 'float':
if (!is_numeric($value)) {
throw new \InvalidArgumentException('Non-numeric value specified');
}
return [
'value' => (double) $value,
'readable-value' => 'double ' . (double) $value,
];
case 'boolean':
case 'bool':
$value = strtolower($value);
switch ($value) {
case 'true':
return [
'value' => true,
'readable-value' => 'boolean ' . $value,
];
case 'false':
return [
'value' => false,
'readable-value' => 'boolean ' . $value,
];
default:
throw new \InvalidArgumentException('Unable to parse value as boolean');
}
case 'null':
return [
'value' => null,
'readable-value' => 'null',
];
case 'string':
$value = (string) $value;
return [
'value' => $value,
'readable-value' => ($value === '') ? 'empty string' : 'string ' . $value,
];
default:
throw new \InvalidArgumentException('Invalid type');
}
}
/**
* @param array $configNames
* @param mixed $existingValues
* @param mixed $value
* @param bool $updateOnly
* @return array merged value
* @throws \UnexpectedValueException
*/
protected function mergeArrayValue(array $configNames, $existingValues, $value, $updateOnly) {
$configName = array_shift($configNames);
if (!is_array($existingValues)) {
$existingValues = [];
}
if (!empty($configNames)) {
if (isset($existingValues[$configName])) {
$existingValue = $existingValues[$configName];
} else {
$existingValue = [];
}
$existingValues[$configName] = $this->mergeArrayValue($configNames, $existingValue, $value, $updateOnly);
} else {
if (!isset($existingValues[$configName]) && $updateOnly) {
throw new \UnexpectedValueException('Config parameter does not exist');
}
$existingValues[$configName] = $value;
}
return $existingValues;
}
}

View File

@ -50,32 +50,31 @@ class DeleteConfigTest extends TestCase {
$this->command = new DeleteConfig($systemConfig);
}
public function deleteData() {
return [
[
'name',
'name1',
true,
true,
0,
'info',
],
[
'name',
'name2',
true,
false,
0,
'info',
],
[
'name',
'name3',
false,
false,
0,
'info',
],
[
'name',
'name4',
false,
true,
1,
@ -105,7 +104,7 @@ class DeleteConfigTest extends TestCase {
$this->consoleInput->expects($this->once())
->method('getArgument')
->with('name')
->willReturn($configName);
->willReturn([$configName]);
$this->consoleInput->expects($this->any())
->method('hasParameterOption')
->with('--error-if-not-exists')
@ -117,4 +116,103 @@ class DeleteConfigTest extends TestCase {
$this->assertSame($expectedReturn, $this->invokePrivate($this->command, 'execute', [$this->consoleInput, $this->consoleOutput]));
}
public function deleteArrayData() {
return [
[
['name', 'sub'],
true,
false,
true,
true,
0,
'info',
],
[
['name', 'sub', '2sub'],
true,
false,
['sub' => ['2sub' => 1], 'sub2' => false],
['sub' => [], 'sub2' => false],
0,
'info',
],
[
['name', 'sub3'],
true,
false,
['sub' => ['2sub' => 1], 'sub2' => false],
['sub' => ['2sub' => 1], 'sub2' => false],
0,
'info',
],
[
['name', 'sub'],
false,
true,
true,
true,
1,
'error',
],
[
['name', 'sub'],
true,
true,
true,
true,
1,
'error',
],
[
['name', 'sub3'],
true,
true,
['sub' => ['2sub' => 1], 'sub2' => false],
['sub' => ['2sub' => 1], 'sub2' => false],
1,
'error',
],
];
}
/**
* @dataProvider deleteArrayData
*
* @param string[] $configNames
* @param bool $configKeyExists
* @param bool $checkIfKeyExists
* @param mixed $configValue
* @param mixed $updateValue
* @param int $expectedReturn
* @param string $expectedMessage
*/
public function testArrayDelete(array $configNames, $configKeyExists, $checkIfKeyExists, $configValue, $updateValue, $expectedReturn, $expectedMessage) {
$this->systemConfig->expects(($checkIfKeyExists) ? $this->once() : $this->never())
->method('getKeys')
->willReturn($configKeyExists ? [$configNames[0]] : []);
$this->systemConfig->expects(($configKeyExists) ? $this->once() : $this->never())
->method('getValue')
->willReturn($configValue);
$this->systemConfig->expects(($expectedReturn === 0) ? $this->once() : $this->never())
->method('setValue')
->with($configNames[0], $updateValue);
$this->consoleInput->expects($this->once())
->method('getArgument')
->with('name')
->willReturn($configNames);
$this->consoleInput->expects($this->any())
->method('hasParameterOption')
->with('--error-if-not-exists')
->willReturn($checkIfKeyExists);
$this->consoleOutput->expects($this->any())
->method('writeln')
->with($this->stringContains($expectedMessage));
$this->assertSame($expectedReturn, $this->invokePrivate($this->command, 'execute', [$this->consoleInput, $this->consoleOutput]));
}
}

View File

@ -90,13 +90,19 @@ class GetConfigTest extends TestCase {
['name', ['a' => 1, 'b' => 2], true, null, false, 'json', 0, json_encode(['a' => 1, 'b' => 2])],
['name', ['a' => 1, 'b' => 2], true, null, false, 'plain', 0, "a: 1\nb: 2"],
// Nested depth
[['name', 'a'], ['a' => 1, 'b' => 2], true, null, false, 'json', 0, json_encode(1)],
[['name', 'a'], ['a' => 1, 'b' => 2], true, null, false, 'plain', 0, '1'],
[['name', 'c'], ['a' => 1, 'b' => 2], true, true, true, 'json', 0, json_encode(true)],
[['name', 'c'], ['a' => 1, 'b' => 2], true, true, false, 'json', 1, null],
];
}
/**
* @dataProvider getData
*
* @param string $configName
* @param string[] $configNames
* @param mixed $value
* @param bool $configExists
* @param mixed $defaultValue
@ -105,7 +111,13 @@ class GetConfigTest extends TestCase {
* @param int $expectedReturn
* @param string $expectedMessage
*/
public function testGet($configName, $value, $configExists, $defaultValue, $hasDefault, $outputFormat, $expectedReturn, $expectedMessage) {
public function testGet($configNames, $value, $configExists, $defaultValue, $hasDefault, $outputFormat, $expectedReturn, $expectedMessage) {
if (is_array($configNames)) {
$configName = $configNames[0];
} else {
$configName = $configNames;
$configNames = [$configName];
}
$this->systemConfig->expects($this->atLeastOnce())
->method('getKeys')
->willReturn($configExists ? [$configName] : []);
@ -122,7 +134,7 @@ class GetConfigTest extends TestCase {
$this->consoleInput->expects($this->once())
->method('getArgument')
->with('name')
->willReturn($configName);
->willReturn($configNames);
$this->consoleInput->expects($this->any())
->method('getOption')
->willReturnMap([

View File

@ -53,63 +53,123 @@ class SetConfigTest extends TestCase {
public function setData() {
return [
[
'name',
'newvalue',
true,
true,
true,
'info',
],
[
'name',
'newvalue',
false,
true,
false,
'comment',
],
[['name'], 'newvalue', null, 'newvalue'],
[['a', 'b', 'c'], 'foobar', null, ['b' => ['c' => 'foobar']]],
[['a', 'b', 'c'], 'foobar', ['b' => ['d' => 'barfoo']], ['b' => ['d' => 'barfoo', 'c' => 'foobar']]],
];
}
/**
* @dataProvider setData
*
* @param string $configName
* @param mixed $newValue
* @param bool $configExists
* @param bool $updateOnly
* @param bool $updated
* @param string $expectedMessage
* @param array $configNames
* @param string $newValue
* @param mixed $existingData
* @param mixed $expectedValue
*/
public function testSet($configName, $newValue, $configExists, $updateOnly, $updated, $expectedMessage) {
public function testSet($configNames, $newValue, $existingData, $expectedValue) {
$this->systemConfig->expects($this->once())
->method('getKeys')
->willReturn($configExists ? [$configName] : []);
if ($updated) {
$this->systemConfig->expects($this->once())
->method('setValue')
->with($configName, $newValue);
}
->method('setValue')
->with($configNames[0], $expectedValue);
$this->systemConfig->method('getValue')
->with($configNames[0])
->willReturn($existingData);
$this->consoleInput->expects($this->once())
->method('getArgument')
->with('name')
->willReturn($configName);
$this->consoleInput->expects($this->any())
->method('getOption')
->with('value')
->willReturn($newValue);
$this->consoleInput->expects($this->any())
->method('hasParameterOption')
->with('--update-only')
->willReturn($updateOnly);
$this->consoleOutput->expects($this->any())
->method('writeln')
->with($this->stringContains($expectedMessage));
->willReturn($configNames);
$this->consoleInput->method('getOption')
->will($this->returnValueMap([
['value', $newValue],
['type', 'string'],
]));
$this->invokePrivate($this->command, 'execute', [$this->consoleInput, $this->consoleOutput]);
}
public function setUpdateOnlyProvider() {
return [
[['name'], null],
[['a', 'b', 'c'], null],
[['a', 'b', 'c'], ['b' => 'foobar']],
[['a', 'b', 'c'], ['b' => ['d' => 'foobar']]],
];
}
/**
* @dataProvider setUpdateOnlyProvider
* @expectedException \UnexpectedValueException
*/
public function testSetUpdateOnly($configNames, $existingData) {
$this->systemConfig->expects($this->never())
->method('setValue');
$this->systemConfig->method('getValue')
->with($configNames[0])
->willReturn($existingData);
$this->systemConfig->method('getKeys')
->willReturn($existingData ? $configNames[0] : []);
$this->consoleInput->expects($this->once())
->method('getArgument')
->with('name')
->willReturn($configNames);
$this->consoleInput->method('getOption')
->will($this->returnValueMap([
['value', 'foobar'],
['type', 'string'],
['update-only', true],
]));
$this->invokePrivate($this->command, 'execute', [$this->consoleInput, $this->consoleOutput]);
}
public function castValueProvider() {
return [
[null, 'string', ['value' => '', 'readable-value' => 'empty string']],
['abc', 'string', ['value' => 'abc', 'readable-value' => 'string abc']],
['123', 'integer', ['value' => 123, 'readable-value' => 'integer 123']],
['456', 'int', ['value' => 456, 'readable-value' => 'integer 456']],
['2.25', 'double', ['value' => 2.25, 'readable-value' => 'double 2.25']],
['0.5', 'float', ['value' => 0.5, 'readable-value' => 'double 0.5']],
['', 'null', ['value' => null, 'readable-value' => 'null']],
['true', 'boolean', ['value' => true, 'readable-value' => 'boolean true']],
['false', 'bool', ['value' => false, 'readable-value' => 'boolean false']],
];
}
/**
* @dataProvider castValueProvider
*/
public function testCastValue($value, $type, $expectedValue) {
$this->assertSame($expectedValue,
$this->invokePrivate($this->command, 'castValue', [$value, $type])
);
}
public function castValueInvalidProvider() {
return [
['123', 'foobar'],
[null, 'integer'],
['abc', 'integer'],
['76ggg', 'double'],
['true', 'float'],
['foobar', 'boolean'],
];
}
/**
* @dataProvider castValueInvalidProvider
* @expectedException \InvalidArgumentException
*/
public function testCastValueInvalid($value, $type) {
$this->invokePrivate($this->command, 'castValue', [$value, $type]);
}
}