mirror of
https://we.phorge.it/source/phorge.git
synced 2024-11-21 22:32:41 +01:00
Add a local configuration source and a non-environmental ENV config source
Summary: See discussion in T2221. Before we can move configuration to the database, we have a bootstrapping problem: we need database credentials to live //somewhere// if we can't guess them (and we can only really guess localhost / root / no password). Some options for this are: - Have them live in ENV variables. - These are often somewhat unfamiliar to users. - Scripts would become a huge pain -- you'd have to dump a bunch of stuff into ENV. - Some environments have limited ability to set ENV vars. - SSH is also a pain. - Have them live in a normal config file. - This probably isn't really too awful, but: - Since we deploy/upgrade with git, we can't currently let them edit a file which already exists, or their working copy will become dirty. - So they have to copy or create a file, then edit it. - The biggest issue I have with this is that it will be difficult to give specific, easily-followed directions from Setup. The instructions need to be like "Copy template.conf.php to real.conf.php, then edit these keys: x, y, z". This isn't as easy to follow as "run script Y". - Have them live in an abnormal config file with script access (this diff). - I think this is a little better than a normal config file, because we can tell users 'run phabricator/bin/config set mysql.user phabricator' and such, which is easier to follow than editing a config file. I think this is only a marginal improvement over a normal config file and am open to arguments against this approach, but I think it will be a little easier for users to deal with than a normal config file. In most cases they should only need to store three values in this file -- db user/host/pass -- since once we have those we can bootstrap everything else. Normal config files also aren't going away for more advanced users, we're just offering a simple alternative for most users. This also adds an ENVIRONMENT file as an alternative to PHABRICATOR_ENV. This is just a simple way to specify the environment if you don't have convenient access to env vars. Test Plan: Ran `config set x y`, verified writes. Wrote to ENVIRONMENT, ran `PHABRICATOR_ENV= ./bin/repository`. Reviewers: btrahan, vrana, codeblock Reviewed By: codeblock CC: aran Maniphest Tasks: T2221 Differential Revision: https://secure.phabricator.com/D4294
This commit is contained in:
parent
908253f1db
commit
ba489f9d85
10 changed files with 163 additions and 7 deletions
16
.gitignore
vendored
16
.gitignore
vendored
|
@ -1,10 +1,6 @@
|
||||||
.DS_Store
|
.DS_Store
|
||||||
._*
|
._*
|
||||||
/docs/
|
|
||||||
/src/.phutil_module_cache
|
|
||||||
/conf/custom/*
|
|
||||||
/webroot/rsrc/custom
|
/webroot/rsrc/custom
|
||||||
/.divinercache
|
|
||||||
.#*
|
.#*
|
||||||
*#
|
*#
|
||||||
*~
|
*~
|
||||||
|
@ -15,3 +11,15 @@
|
||||||
|
|
||||||
# Arcanist scratch directory
|
# Arcanist scratch directory
|
||||||
/.arc
|
/.arc
|
||||||
|
|
||||||
|
# Diviner
|
||||||
|
/docs/
|
||||||
|
/.divinercache
|
||||||
|
|
||||||
|
# libphutil
|
||||||
|
/src/.phutil_module_cache
|
||||||
|
|
||||||
|
# Configuration
|
||||||
|
/conf/custom/*
|
||||||
|
/conf/local/local.json
|
||||||
|
/conf/local/ENVIRONMENT
|
||||||
|
|
1
bin/config
Symbolic link
1
bin/config
Symbolic link
|
@ -0,0 +1 @@
|
||||||
|
../scripts/setup/manage_config.php
|
0
conf/local/.keep
Normal file
0
conf/local/.keep
Normal file
22
scripts/setup/manage_config.php
Executable file
22
scripts/setup/manage_config.php
Executable file
|
@ -0,0 +1,22 @@
|
||||||
|
#!/usr/bin/env php
|
||||||
|
<?php
|
||||||
|
|
||||||
|
$root = dirname(dirname(dirname(__FILE__)));
|
||||||
|
require_once $root.'/scripts/__init_script__.php';
|
||||||
|
|
||||||
|
$args = new PhutilArgumentParser($argv);
|
||||||
|
$args->setTagline('manage configuration');
|
||||||
|
$args->setSynopsis(<<<EOSYNOPSIS
|
||||||
|
**config** __command__ [__options__]
|
||||||
|
Manage Phabricator configuration.
|
||||||
|
|
||||||
|
EOSYNOPSIS
|
||||||
|
);
|
||||||
|
$args->parseStandardArguments();
|
||||||
|
|
||||||
|
$workflows = array(
|
||||||
|
new PhabricatorConfigManagementSetWorkflow(),
|
||||||
|
new PhutilHelpArgumentWorkflow(),
|
||||||
|
);
|
||||||
|
|
||||||
|
$args->parseWorkflows($workflows);
|
|
@ -687,6 +687,9 @@ phutil_register_library_map(array(
|
||||||
'PhabricatorConfigEntryDAO' => 'applications/config/storage/PhabricatorConfigEntryDAO.php',
|
'PhabricatorConfigEntryDAO' => 'applications/config/storage/PhabricatorConfigEntryDAO.php',
|
||||||
'PhabricatorConfigFileSource' => 'infrastructure/env/PhabricatorConfigFileSource.php',
|
'PhabricatorConfigFileSource' => 'infrastructure/env/PhabricatorConfigFileSource.php',
|
||||||
'PhabricatorConfigListController' => 'applications/config/controller/PhabricatorConfigListController.php',
|
'PhabricatorConfigListController' => 'applications/config/controller/PhabricatorConfigListController.php',
|
||||||
|
'PhabricatorConfigLocalSource' => 'infrastructure/env/PhabricatorConfigLocalSource.php',
|
||||||
|
'PhabricatorConfigManagementSetWorkflow' => 'infrastructure/env/management/PhabricatorConfigManagementSetWorkflow.php',
|
||||||
|
'PhabricatorConfigManagementWorkflow' => 'infrastructure/env/management/PhabricatorConfigManagementWorkflow.php',
|
||||||
'PhabricatorConfigProxySource' => 'infrastructure/env/PhabricatorConfigProxySource.php',
|
'PhabricatorConfigProxySource' => 'infrastructure/env/PhabricatorConfigProxySource.php',
|
||||||
'PhabricatorConfigSource' => 'infrastructure/env/PhabricatorConfigSource.php',
|
'PhabricatorConfigSource' => 'infrastructure/env/PhabricatorConfigSource.php',
|
||||||
'PhabricatorConfigStackSource' => 'infrastructure/env/PhabricatorConfigStackSource.php',
|
'PhabricatorConfigStackSource' => 'infrastructure/env/PhabricatorConfigStackSource.php',
|
||||||
|
@ -2000,6 +2003,9 @@ phutil_register_library_map(array(
|
||||||
'PhabricatorConfigEntryDAO' => 'PhabricatorLiskDAO',
|
'PhabricatorConfigEntryDAO' => 'PhabricatorLiskDAO',
|
||||||
'PhabricatorConfigFileSource' => 'PhabricatorConfigProxySource',
|
'PhabricatorConfigFileSource' => 'PhabricatorConfigProxySource',
|
||||||
'PhabricatorConfigListController' => 'PhabricatorConfigController',
|
'PhabricatorConfigListController' => 'PhabricatorConfigController',
|
||||||
|
'PhabricatorConfigLocalSource' => 'PhabricatorConfigProxySource',
|
||||||
|
'PhabricatorConfigManagementSetWorkflow' => 'PhabricatorConfigManagementWorkflow',
|
||||||
|
'PhabricatorConfigManagementWorkflow' => 'PhutilArgumentWorkflow',
|
||||||
'PhabricatorConfigProxySource' => 'PhabricatorConfigSource',
|
'PhabricatorConfigProxySource' => 'PhabricatorConfigSource',
|
||||||
'PhabricatorConfigStackSource' => 'PhabricatorConfigSource',
|
'PhabricatorConfigStackSource' => 'PhabricatorConfigSource',
|
||||||
'PhabricatorContentSourceView' => 'AphrontView',
|
'PhabricatorContentSourceView' => 'AphrontView',
|
||||||
|
|
51
src/infrastructure/env/PhabricatorConfigLocalSource.php
vendored
Normal file
51
src/infrastructure/env/PhabricatorConfigLocalSource.php
vendored
Normal file
|
@ -0,0 +1,51 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
final class PhabricatorConfigLocalSource
|
||||||
|
extends PhabricatorConfigProxySource {
|
||||||
|
|
||||||
|
public function __construct() {
|
||||||
|
$config = $this->loadConfig();
|
||||||
|
$this->setSource(new PhabricatorConfigDictionarySource($config));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setKeys(array $keys) {
|
||||||
|
$result = parent::setKeys($keys);
|
||||||
|
$this->saveConfig();
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function deleteKeys(array $keys) {
|
||||||
|
$result = parent::deleteKeys($keys);
|
||||||
|
$this->saveConfig();
|
||||||
|
return parent::deleteKeys($keys);
|
||||||
|
}
|
||||||
|
|
||||||
|
private function loadConfig() {
|
||||||
|
$path = $this->getConfigPath();
|
||||||
|
if (@file_exists($path)) {
|
||||||
|
$data = @file_get_contents($path);
|
||||||
|
if ($data) {
|
||||||
|
$data = json_decode($data, true);
|
||||||
|
if (is_array($data)) {
|
||||||
|
return $data;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return array();
|
||||||
|
}
|
||||||
|
|
||||||
|
private function saveConfig() {
|
||||||
|
$config = $this->getSource()->getAllKeys();
|
||||||
|
$json = new PhutilJSON();
|
||||||
|
$data = $json->encodeFormatted($config);
|
||||||
|
Filesystem::writeFile($this->getConfigPath(), $data);
|
||||||
|
}
|
||||||
|
|
||||||
|
private function getConfigPath() {
|
||||||
|
$root = dirname(phutil_get_library_root('phabricator'));
|
||||||
|
$path = $root.'/conf/local/local.json';
|
||||||
|
return $path;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -29,15 +29,15 @@ abstract class PhabricatorConfigProxySource
|
||||||
}
|
}
|
||||||
|
|
||||||
public function canWrite() {
|
public function canWrite() {
|
||||||
return $this->getSource->canWrite();
|
return $this->getSource()->canWrite();
|
||||||
}
|
}
|
||||||
|
|
||||||
public function setKeys(array $keys) {
|
public function setKeys(array $keys) {
|
||||||
return $this->getSource->setKeys();
|
return $this->getSource()->setKeys($keys);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function deleteKeys(array $keys) {
|
public function deleteKeys(array $keys) {
|
||||||
return $this->getSource->deleteKeys();
|
return $this->getSource()->deleteKeys();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
8
src/infrastructure/env/PhabricatorEnv.php
vendored
8
src/infrastructure/env/PhabricatorEnv.php
vendored
|
@ -139,6 +139,14 @@ final class PhabricatorEnv {
|
||||||
$env = idx($_ENV, $env_var);
|
$env = idx($_ENV, $env_var);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!$env) {
|
||||||
|
$root = dirname(phutil_get_library_root('phabricator'));
|
||||||
|
$path = $root.'/conf/local/ENVIRONMENT';
|
||||||
|
if (Filesystem::pathExists($path)) {
|
||||||
|
$env = trim(Filesystem::readFile($path));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return $env;
|
return $env;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
50
src/infrastructure/env/management/PhabricatorConfigManagementSetWorkflow.php
vendored
Normal file
50
src/infrastructure/env/management/PhabricatorConfigManagementSetWorkflow.php
vendored
Normal file
|
@ -0,0 +1,50 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
final class PhabricatorConfigManagementSetWorkflow
|
||||||
|
extends PhabricatorConfigManagementWorkflow {
|
||||||
|
|
||||||
|
protected function didConstruct() {
|
||||||
|
$this
|
||||||
|
->setName('set')
|
||||||
|
->setExamples('**set** __key__ __value__')
|
||||||
|
->setSynopsis('Set a local configuration value.')
|
||||||
|
->setArguments(
|
||||||
|
array(
|
||||||
|
array(
|
||||||
|
'name' => 'args',
|
||||||
|
'wildcard' => true,
|
||||||
|
),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function execute(PhutilArgumentParser $args) {
|
||||||
|
$console = PhutilConsole::getConsole();
|
||||||
|
|
||||||
|
$argv = $args->getArg('args');
|
||||||
|
if (count($argv) == 0) {
|
||||||
|
throw new PhutilArgumentUsageException(
|
||||||
|
"Specify a configuration key and a value to set it to.");
|
||||||
|
}
|
||||||
|
|
||||||
|
$key = $argv[0];
|
||||||
|
|
||||||
|
if (count($argv) == 1) {
|
||||||
|
throw new PhutilArgumentUsageException(
|
||||||
|
"Specify a value to set the key '{$key}' to.");
|
||||||
|
}
|
||||||
|
|
||||||
|
$value = $argv[1];
|
||||||
|
|
||||||
|
if (count($argv) > 2) {
|
||||||
|
throw new PhutilArgumentUsageException(
|
||||||
|
"Too many arguments: expected one key and one value.");
|
||||||
|
}
|
||||||
|
|
||||||
|
$config = new PhabricatorConfigLocalSource();
|
||||||
|
$config->setKeys(array($key => $value));
|
||||||
|
|
||||||
|
$console->writeOut(
|
||||||
|
pht("Set '%s' to '%s' in local configuration.", $key, $value)."\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
10
src/infrastructure/env/management/PhabricatorConfigManagementWorkflow.php
vendored
Normal file
10
src/infrastructure/env/management/PhabricatorConfigManagementWorkflow.php
vendored
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
abstract class PhabricatorConfigManagementWorkflow
|
||||||
|
extends PhutilArgumentWorkflow {
|
||||||
|
|
||||||
|
final public function isExecutable() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
Loading…
Reference in a new issue