1
0
Fork 0
mirror of https://we.phorge.it/source/phorge.git synced 2024-12-30 17:30:59 +01:00

Allow bin/config to affect database configuration and migrate between local and database configuration

Summary: Fixes T4018. Basically hits the bullet points in that task description except the "ideally" one.

Test Plan:
ran bin/config migrate and saw sensible output.

```
~> ./bin/config migrate
Migrating file-based config to more modern config...
Skipping config of source type PhabricatorConfigDatabaseSource...
Skipping config of source type PhabricatorConfigLocalSource...
Skipping config of source type PhabricatorConfigDefaultSource...
Done. Migrated 0 keys.
```

Reviewers: epriestley

Reviewed By: epriestley

Subscribers: hach-que, epriestley, Korvin

Maniphest Tasks: T4018

Differential Revision: https://secure.phabricator.com/D10490
This commit is contained in:
Bob Trahan 2014-10-08 16:15:05 -07:00
parent f4604ae147
commit c0848bca6d
9 changed files with 251 additions and 42 deletions

View file

@ -1380,6 +1380,7 @@ phutil_register_library_map(array(
'PhabricatorConfigManagementDeleteWorkflow' => 'applications/config/management/PhabricatorConfigManagementDeleteWorkflow.php', 'PhabricatorConfigManagementDeleteWorkflow' => 'applications/config/management/PhabricatorConfigManagementDeleteWorkflow.php',
'PhabricatorConfigManagementGetWorkflow' => 'applications/config/management/PhabricatorConfigManagementGetWorkflow.php', 'PhabricatorConfigManagementGetWorkflow' => 'applications/config/management/PhabricatorConfigManagementGetWorkflow.php',
'PhabricatorConfigManagementListWorkflow' => 'applications/config/management/PhabricatorConfigManagementListWorkflow.php', 'PhabricatorConfigManagementListWorkflow' => 'applications/config/management/PhabricatorConfigManagementListWorkflow.php',
'PhabricatorConfigManagementMigrateWorkflow' => 'applications/config/management/PhabricatorConfigManagementMigrateWorkflow.php',
'PhabricatorConfigManagementSetWorkflow' => 'applications/config/management/PhabricatorConfigManagementSetWorkflow.php', 'PhabricatorConfigManagementSetWorkflow' => 'applications/config/management/PhabricatorConfigManagementSetWorkflow.php',
'PhabricatorConfigManagementWorkflow' => 'applications/config/management/PhabricatorConfigManagementWorkflow.php', 'PhabricatorConfigManagementWorkflow' => 'applications/config/management/PhabricatorConfigManagementWorkflow.php',
'PhabricatorConfigOption' => 'applications/config/option/PhabricatorConfigOption.php', 'PhabricatorConfigOption' => 'applications/config/option/PhabricatorConfigOption.php',
@ -4342,6 +4343,7 @@ phutil_register_library_map(array(
'PhabricatorConfigManagementDeleteWorkflow' => 'PhabricatorConfigManagementWorkflow', 'PhabricatorConfigManagementDeleteWorkflow' => 'PhabricatorConfigManagementWorkflow',
'PhabricatorConfigManagementGetWorkflow' => 'PhabricatorConfigManagementWorkflow', 'PhabricatorConfigManagementGetWorkflow' => 'PhabricatorConfigManagementWorkflow',
'PhabricatorConfigManagementListWorkflow' => 'PhabricatorConfigManagementWorkflow', 'PhabricatorConfigManagementListWorkflow' => 'PhabricatorConfigManagementWorkflow',
'PhabricatorConfigManagementMigrateWorkflow' => 'PhabricatorConfigManagementWorkflow',
'PhabricatorConfigManagementSetWorkflow' => 'PhabricatorConfigManagementWorkflow', 'PhabricatorConfigManagementSetWorkflow' => 'PhabricatorConfigManagementWorkflow',
'PhabricatorConfigManagementWorkflow' => 'PhabricatorManagementWorkflow', 'PhabricatorConfigManagementWorkflow' => 'PhabricatorManagementWorkflow',
'PhabricatorConfigOption' => array( 'PhabricatorConfigOption' => array(

View file

@ -59,7 +59,10 @@ final class PhabricatorConfigIgnoreController
} }
PhabricatorConfigEditor::storeNewValue( PhabricatorConfigEditor::storeNewValue(
$config_entry, $list, $this->getRequest()); $this->getRequest()->getUser(),
$config_entry,
$list,
PhabricatorContentSource::newFromRequest($this->getRequest()));
} }
} }

View file

@ -113,9 +113,10 @@ final class PhabricatorConfigEditor
} }
public static function storeNewValue( public static function storeNewValue(
PhabricatorUser $user,
PhabricatorConfigEntry $config_entry, PhabricatorConfigEntry $config_entry,
$value, $value,
AphrontRequest $request) { PhabricatorContentSource $source) {
$xaction = id(new PhabricatorConfigTransaction()) $xaction = id(new PhabricatorConfigTransaction())
->setTransactionType(PhabricatorConfigTransaction::TYPE_EDIT) ->setTransactionType(PhabricatorConfigTransaction::TYPE_EDIT)
@ -126,9 +127,30 @@ final class PhabricatorConfigEditor
)); ));
$editor = id(new PhabricatorConfigEditor()) $editor = id(new PhabricatorConfigEditor())
->setActor($request->getUser()) ->setActor($user)
->setContinueOnNoEffect(true) ->setContinueOnNoEffect(true)
->setContentSourceFromRequest($request); ->setContentSource($source);
$editor->applyTransactions($config_entry, array($xaction));
}
public static function deleteConfig(
PhabricatorUser $user,
PhabricatorConfigEntry $config_entry,
PhabricatorContentSource $source) {
$xaction = id(new PhabricatorConfigTransaction())
->setTransactionType(PhabricatorConfigTransaction::TYPE_EDIT)
->setNewValue(
array(
'deleted' => true,
'value' => null,
));
$editor = id(new PhabricatorConfigEditor())
->setActor($user)
->setContinueOnNoEffect(true)
->setContentSource($source);
$editor->applyTransactions($config_entry, array($xaction)); $editor->applyTransactions($config_entry, array($xaction));
} }

View file

@ -7,9 +7,14 @@ final class PhabricatorConfigManagementDeleteWorkflow
$this $this
->setName('delete') ->setName('delete')
->setExamples('**delete** __key__') ->setExamples('**delete** __key__')
->setSynopsis('Delete a local configuration value.') ->setSynopsis(pht('Delete a local configuration value.'))
->setArguments( ->setArguments(
array( array(
array(
'name' => 'database',
'help' => pht('Delete configuration in the database instead of '.
'in local configuration.'),
),
array( array(
'name' => 'args', 'name' => 'args',
'wildcard' => true, 'wildcard' => true,
@ -22,28 +27,50 @@ final class PhabricatorConfigManagementDeleteWorkflow
$argv = $args->getArg('args'); $argv = $args->getArg('args');
if (count($argv) == 0) { if (count($argv) == 0) {
throw new PhutilArgumentUsageException( throw new PhutilArgumentUsageException(pht(
'Specify a configuration key to delete.'); 'Specify a configuration key to delete.'));
} }
$key = $argv[0]; $key = $argv[0];
if (count($argv) > 1) { if (count($argv) > 1) {
throw new PhutilArgumentUsageException( throw new PhutilArgumentUsageException(pht(
'Too many arguments: expected one key.'); 'Too many arguments: expected one key.'));
} }
$config = new PhabricatorConfigLocalSource();
$use_database = $args->getArg('database');
if ($use_database) {
$config = new PhabricatorConfigDatabaseSource('default');
$config_type = 'database';
} else {
$config = new PhabricatorConfigLocalSource();
$config_type = 'local';
}
$values = $config->getKeys(array($key)); $values = $config->getKeys(array($key));
if (!$values) { if (!$values) {
throw new PhutilArgumentUsageException( throw new PhutilArgumentUsageException(pht(
"Configuration key '{$key}' is not set in local configuration!"); "Configuration key '%s' is not set in %s configuration!",
$key,
$config_type));
} }
$config->deleteKeys(array($key)); if ($use_database) {
$config_entry = id(new PhabricatorConfigOption())
->loadOneWhere(
'namespace = %s and key = %s',
'default',
$key);
PhabricatorConfigEditor::deleteConfig(
$this->getViewer(),
$config_entry,
PhabricatorContentSource::newConsoleSource());
} else {
$config->deleteKeys(array($key));
}
$console->writeOut( $console->writeOut(
pht("Deleted '%s' from local configuration.", $key)."\n"); pht("Deleted '%s' from %s configuration.", $key, $config_type)."\n");
} }
} }

View file

@ -40,15 +40,60 @@ final class PhabricatorConfigManagementGetWorkflow
"keys."); "keys.");
} }
$values = array();
$config = new PhabricatorConfigLocalSource(); $config = new PhabricatorConfigLocalSource();
$values = $config->getKeys(array($key)); $local_value = $config->getKeys(array($key));
if (empty($local_value)) {
$values['local'] = array(
'key' => $key,
'value' => null,
'status' => 'unset',
'errorInfo' => null,
);
} else {
$values['local'] = array(
'key' => $key,
'value' => reset($local_value),
'status' => 'set',
'errorInfo' => null,
);
}
$database_config = new PhabricatorConfigDatabaseSource('default');
try {
$database_value = $database_config->getKeys(array($key));
if (empty($database_value)) {
$values['database'] = array(
'key' => $key,
'value' => null,
'status' => 'unset',
'errorInfo' => null,
);
} else {
$values['database'] = array(
'key' => $key,
'value' => reset($database_value),
'status' => 'set',
'errorInfo' => null,
);
}
} catch (Exception $e) {
$values['database'] = array(
'key' => $key,
'value' => null,
'status' => 'error',
'errorInfo' => pht('Database source is not configured properly'),
);
}
$result = array(); $result = array();
foreach ($values as $key => $value) { foreach ($values as $source => $value) {
$result[] = array( $result[] = array(
'key' => $key, 'key' => $value['key'],
'source' => 'local', 'source' => $source,
'value' => $value, 'value' => $value['value'],
'status' => $value['status'],
'errorInfo' => $value['errorInfo'],
); );
} }
$result = array( $result = array(

View file

@ -0,0 +1,75 @@
<?php
final class PhabricatorConfigManagementMigrateWorkflow
extends PhabricatorConfigManagementWorkflow {
protected function didConstruct() {
$this
->setName('migrate')
->setExamples('**migrate**')
->setSynopsis(pht(
'Migrate file-based configuration to more modern storage.'));
}
public function execute(PhutilArgumentParser $args) {
$console = PhutilConsole::getConsole();
$key_count = 0;
$options = PhabricatorApplicationConfigOptions::loadAllOptions();
$local_config = new PhabricatorConfigLocalSource();
$database_config = new PhabricatorConfigDatabaseSource('default');
$config_sources = PhabricatorEnv::getConfigSourceStack()->getStack();
$console->writeOut(
pht('Migrating file-based config to more modern config...')."\n");
foreach ($config_sources as $config_source) {
if (!($config_source instanceof PhabricatorConfigFileSource)) {
$console->writeOut(
pht('Skipping config of source type %s...',
get_class($config_source))."\n");
continue;
}
$console->writeOut(pht('Migrating file source...')."\n");
$all_keys = $config_source->getAllKeys();
foreach ($all_keys as $key => $value) {
$option = idx($options, $key);
if (!$option) {
$console->writeOut(pht('Skipping obsolete option: %s', $key)."\n");
continue;
}
$in_local = $local_config->getKeys(array($option->getKey()));
if ($in_local) {
$console->writeOut(pht(
'Skipping option "%s"; already in local config.', $key)."\n");
continue;
}
$is_locked = $option->getLocked();
if ($is_locked) {
$local_config->setKeys(array($option->getKey() => $value));
$key_count++;
$console->writeOut(pht(
'Migrated option "%s" from file to local config.', $key)."\n");
} else {
$in_database = $database_config->getKeys(array($option->getKey()));
if ($in_database) {
$console->writeOut(pht(
'Skipping option "%s"; already in database config.', $key)."\n");
continue;
} else {
PhabricatorConfigEditor::deleteConfig(
$this->getViewer(),
$option,
PhabricatorContentSource::newFromConsole());
$key_count++;
$console->writeOut(pht(
'Migrated option "%s" from file to local config.', $key)."\n");
}
}
}
}
$console->writeOut(pht(
'Done. Migrated %d keys.', $key_count)."\n");
return 0;
}
}

View file

@ -7,9 +7,14 @@ final class PhabricatorConfigManagementSetWorkflow
$this $this
->setName('set') ->setName('set')
->setExamples('**set** __key__ __value__') ->setExamples('**set** __key__ __value__')
->setSynopsis('Set a local configuration value.') ->setSynopsis(pht('Set a local configuration value.'))
->setArguments( ->setArguments(
array( array(
array(
'name' => 'database',
'help' => pht('Update configuration in the database instead of '.
'in local configuration.'),
),
array( array(
'name' => 'args', 'name' => 'args',
'wildcard' => true, 'wildcard' => true,
@ -21,29 +26,31 @@ final class PhabricatorConfigManagementSetWorkflow
$console = PhutilConsole::getConsole(); $console = PhutilConsole::getConsole();
$argv = $args->getArg('args'); $argv = $args->getArg('args');
if (count($argv) == 0) { if (count($argv) == 0) {
throw new PhutilArgumentUsageException( throw new PhutilArgumentUsageException(pht(
'Specify a configuration key and a value to set it to.'); 'Specify a configuration key and a value to set it to.'));
} }
$key = $argv[0]; $key = $argv[0];
if (count($argv) == 1) { if (count($argv) == 1) {
throw new PhutilArgumentUsageException( throw new PhutilArgumentUsageException(pht(
"Specify a value to set the key '{$key}' to."); "Specify a value to set the key '%s' to.",
$key));
} }
$value = $argv[1]; $value = $argv[1];
if (count($argv) > 2) { if (count($argv) > 2) {
throw new PhutilArgumentUsageException( throw new PhutilArgumentUsageException(pht(
'Too many arguments: expected one key and one value.'); 'Too many arguments: expected one key and one value.'));
} }
$options = PhabricatorApplicationConfigOptions::loadAllOptions(); $options = PhabricatorApplicationConfigOptions::loadAllOptions();
if (empty($options[$key])) { if (empty($options[$key])) {
throw new PhutilArgumentUsageException( throw new PhutilArgumentUsageException(pht(
"No such configuration key '{$key}'! Use `config list` to list all ". "No such configuration key '%s'! Use `config list` to list all ".
"keys."); "keys.",
$key));
} }
$option = $options[$key]; $option = $options[$key];
@ -57,8 +64,10 @@ final class PhabricatorConfigManagementSetWorkflow
break; break;
case 'int': case 'int':
if (!ctype_digit($value)) { if (!ctype_digit($value)) {
throw new PhutilArgumentUsageException( throw new PhutilArgumentUsageException(pht(
"Config key '{$key}' is of type '{$type}'. Specify an integer."); "Config key '%s' is of type '%s'. Specify an integer.",
$key,
$type));
} }
$value = (int)$value; $value = (int)$value;
break; break;
@ -68,19 +77,30 @@ final class PhabricatorConfigManagementSetWorkflow
} else if ($value == 'false') { } else if ($value == 'false') {
$value = false; $value = false;
} else { } else {
throw new PhutilArgumentUsageException( throw new PhutilArgumentUsageException(pht(
"Config key '{$key}' is of type '{$type}'. ". "Config key '%s' is of type '%s'. ".
"Specify 'true' or 'false'."); "Specify 'true' or 'false'.",
$key,
$type));
} }
break; break;
default: default:
$value = json_decode($value, true); $value = json_decode($value, true);
if (!is_array($value)) { if (!is_array($value)) {
throw new PhutilArgumentUsageException( throw new PhutilArgumentUsageException(pht(
"Config key '{$key}' is of type '{$type}'. Specify it in JSON."); "Config key '%s' is of type '%s'. Specify it in JSON.",
$key,
$type));
} }
break; 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.',
$key));
}
try { try {
$option->getGroup()->validateOption($option, $value); $option->getGroup()->validateOption($option, $value);
@ -89,11 +109,22 @@ final class PhabricatorConfigManagementSetWorkflow
throw new PhutilArgumentUsageException($validation->getMessage()); throw new PhutilArgumentUsageException($validation->getMessage());
} }
$config = new PhabricatorConfigLocalSource(); if ($use_database) {
$config->setKeys(array($key => $value)); $config_type = 'database';
PhabricatorConfigEditor::storeNewValue(
$this->getViewer(),
id(new PhabricatorConfigEntry())
->loadOneWhere('namespace = %s AND key = %s', 'default', $key),
$value,
PhabricatorContentSource::newConsoleSource());
} else {
$config_type = 'local';
id(new PhabricatorConfigLocalSource())
->setKeys(array($key => $value));
}
$console->writeOut( $console->writeOut(
pht("Set '%s' in local configuration.", $key)."\n"); pht("Set '%s' in %s configuration.", $key, $config_type)."\n");
} }
} }

View file

@ -104,9 +104,10 @@ final class PhabricatorApplicationEditController
PhabricatorPolicyCapability::CAN_EDIT); PhabricatorPolicyCapability::CAN_EDIT);
PhabricatorConfigEditor::storeNewValue( PhabricatorConfigEditor::storeNewValue(
$user,
$config_entry, $config_entry,
$value, $value,
$this->getRequest()); PhabricatorContentSource::newFromRequest($this->getRequest()));
} }
return id(new AphrontRedirectResponse())->setURI($view_uri); return id(new AphrontRedirectResponse())->setURI($view_uri);

View file

@ -90,7 +90,10 @@ final class PhabricatorApplicationUninstallController
} }
PhabricatorConfigEditor::storeNewValue( PhabricatorConfigEditor::storeNewValue(
$config_entry, $list, $this->getRequest()); $this->getRequest()->getUser(),
$config_entry,
$list,
PhabricatorContentSource::newFromRequest($this->getRequest()));
} }
} }