1
0
Fork 0
mirror of https://we.phorge.it/source/phorge.git synced 2024-12-01 03:02:43 +01:00
phorge-phorge/src/applications/config/management/PhabricatorConfigManagementSetWorkflow.php
epriestley 4236952cdb Add a bin/config set <key> --stdin < value.json flag to make CLI configuration of complex values easier
Summary:
Depends on D19003. Ref T12677. Ref T13053. For the first time, we're requiring CLI configuration of a complex value (not just a string, integer, bool, etc) to do something fairly standard (send mail).

Users sometimes have very reasonable difficulty figuring out how to `./bin/config set key <some big JSON mess>`. Provide an easy way to handle this and make sure it gets appropriate callouts in the documentation.

(Also, hide the `cluster.mailers` value rather than just locking it, since it may have API keys or SMTP passwords.)

Test Plan: Read documentation, used old and new flags to set configuration.

Reviewers: amckinley

Reviewed By: amckinley

Maniphest Tasks: T13053, T12677

Differential Revision: https://secure.phabricator.com/D19004
2018-02-08 06:09:09 -08:00

150 lines
4.3 KiB
PHP

<?php
final class PhabricatorConfigManagementSetWorkflow
extends PhabricatorConfigManagementWorkflow {
protected function didConstruct() {
$this
->setName('set')
->setExamples(
"**set** __key__ __value__\n".
"**set** __key__ --stdin < value.json")
->setSynopsis(pht('Set a local configuration value.'))
->setArguments(
array(
array(
'name' => 'database',
'help' => pht(
'Update configuration in the database instead of '.
'in local configuration.'),
),
array(
'name' => 'stdin',
'help' => pht('Read option value from stdin.'),
),
array(
'name' => 'args',
'wildcard' => true,
),
));
}
public function execute(PhutilArgumentParser $args) {
$console = PhutilConsole::getConsole();
$argv = $args->getArg('args');
if (count($argv) == 0) {
throw new PhutilArgumentUsageException(
pht('Specify a configuration key and a value to set it to.'));
}
$is_stdin = $args->getArg('stdin');
$key = $argv[0];
if ($is_stdin) {
if (count($argv) > 1) {
throw new PhutilArgumentUsageException(
pht(
'Too many arguments: expected only a key when using "--stdin".'));
}
fprintf(STDERR, tsprintf("%s\n", pht('Reading value from stdin...')));
$value = file_get_contents('php://stdin');
} else {
if (count($argv) == 1) {
throw new PhutilArgumentUsageException(
pht(
"Specify a value to set the key '%s' to.",
$key));
}
if (count($argv) > 2) {
throw new PhutilArgumentUsageException(
pht(
'Too many arguments: expected one key and one value.'));
}
$value = $argv[1];
}
$options = PhabricatorApplicationConfigOptions::loadAllOptions();
if (empty($options[$key])) {
throw new PhutilArgumentUsageException(
pht(
"No such configuration key '%s'! Use `%s` to list all keys.",
$key,
'config list'));
}
$option = $options[$key];
$type = $option->newOptionType();
if ($type) {
try {
$value = $type->newValueFromCommandLineValue(
$option,
$value);
$type->validateStoredValue($option, $value);
} catch (PhabricatorConfigValidationException $ex) {
throw new PhutilArgumentUsageException($ex->getMessage());
}
} else {
// NOTE: For now, this handles both "wild" values and custom types.
$type = $option->getType();
switch ($type) {
default:
$value = json_decode($value, true);
if (!is_array($value)) {
switch ($type) {
default:
$message = pht(
'Config key "%s" is of type "%s". Specify it in JSON.',
$key,
$type);
break;
}
throw new PhutilArgumentUsageException($message);
}
break;
}
}
$use_database = $args->getArg('database');
if ($option->getLocked() && $use_database) {
throw new PhutilArgumentUsageException(
pht(
'Config key "%s" is locked and can only be set in local '.
'configuration. To learn more, see "%s" in the documentation.',
$key,
pht('Configuration Guide: Locked and Hidden Configuration')));
}
try {
$option->getGroup()->validateOption($option, $value);
} catch (PhabricatorConfigValidationException $validation) {
// Convert this into a usage exception so we don't dump a stack trace.
throw new PhutilArgumentUsageException($validation->getMessage());
}
if ($use_database) {
$config_type = 'database';
$config_entry = PhabricatorConfigEntry::loadConfigEntry($key);
$config_entry->setValue($value);
// If the entry has been deleted, resurrect it.
$config_entry->setIsDeleted(0);
$config_entry->save();
} else {
$config_type = 'local';
id(new PhabricatorConfigLocalSource())
->setKeys(array($key => $value));
}
$console->writeOut(
"%s\n",
pht("Set '%s' in %s configuration.", $key, $config_type));
}
}