Skip to content

Commit ba489f9

Browse files
author
epriestley
committed
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
1 parent 908253f commit ba489f9

10 files changed

+163
-7
lines changed

.gitignore

+12-4
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,6 @@
11
.DS_Store
22
._*
3-
/docs/
4-
/src/.phutil_module_cache
5-
/conf/custom/*
63
/webroot/rsrc/custom
7-
/.divinercache
84
.#*
95
*#
106
*~
@@ -15,3 +11,15 @@
1511

1612
# Arcanist scratch directory
1713
/.arc
14+
15+
# Diviner
16+
/docs/
17+
/.divinercache
18+
19+
# libphutil
20+
/src/.phutil_module_cache
21+
22+
# Configuration
23+
/conf/custom/*
24+
/conf/local/local.json
25+
/conf/local/ENVIRONMENT

bin/config

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
../scripts/setup/manage_config.php

conf/local/.keep

Whitespace-only changes.

scripts/setup/manage_config.php

+22
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
#!/usr/bin/env php
2+
<?php
3+
4+
$root = dirname(dirname(dirname(__FILE__)));
5+
require_once $root.'/scripts/__init_script__.php';
6+
7+
$args = new PhutilArgumentParser($argv);
8+
$args->setTagline('manage configuration');
9+
$args->setSynopsis(<<<EOSYNOPSIS
10+
**config** __command__ [__options__]
11+
Manage Phabricator configuration.
12+
13+
EOSYNOPSIS
14+
);
15+
$args->parseStandardArguments();
16+
17+
$workflows = array(
18+
new PhabricatorConfigManagementSetWorkflow(),
19+
new PhutilHelpArgumentWorkflow(),
20+
);
21+
22+
$args->parseWorkflows($workflows);

src/__phutil_library_map__.php

+6
Original file line numberDiff line numberDiff line change
@@ -687,6 +687,9 @@
687687
'PhabricatorConfigEntryDAO' => 'applications/config/storage/PhabricatorConfigEntryDAO.php',
688688
'PhabricatorConfigFileSource' => 'infrastructure/env/PhabricatorConfigFileSource.php',
689689
'PhabricatorConfigListController' => 'applications/config/controller/PhabricatorConfigListController.php',
690+
'PhabricatorConfigLocalSource' => 'infrastructure/env/PhabricatorConfigLocalSource.php',
691+
'PhabricatorConfigManagementSetWorkflow' => 'infrastructure/env/management/PhabricatorConfigManagementSetWorkflow.php',
692+
'PhabricatorConfigManagementWorkflow' => 'infrastructure/env/management/PhabricatorConfigManagementWorkflow.php',
690693
'PhabricatorConfigProxySource' => 'infrastructure/env/PhabricatorConfigProxySource.php',
691694
'PhabricatorConfigSource' => 'infrastructure/env/PhabricatorConfigSource.php',
692695
'PhabricatorConfigStackSource' => 'infrastructure/env/PhabricatorConfigStackSource.php',
@@ -2000,6 +2003,9 @@
20002003
'PhabricatorConfigEntryDAO' => 'PhabricatorLiskDAO',
20012004
'PhabricatorConfigFileSource' => 'PhabricatorConfigProxySource',
20022005
'PhabricatorConfigListController' => 'PhabricatorConfigController',
2006+
'PhabricatorConfigLocalSource' => 'PhabricatorConfigProxySource',
2007+
'PhabricatorConfigManagementSetWorkflow' => 'PhabricatorConfigManagementWorkflow',
2008+
'PhabricatorConfigManagementWorkflow' => 'PhutilArgumentWorkflow',
20032009
'PhabricatorConfigProxySource' => 'PhabricatorConfigSource',
20042010
'PhabricatorConfigStackSource' => 'PhabricatorConfigSource',
20052011
'PhabricatorContentSourceView' => 'AphrontView',
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
<?php
2+
3+
final class PhabricatorConfigLocalSource
4+
extends PhabricatorConfigProxySource {
5+
6+
public function __construct() {
7+
$config = $this->loadConfig();
8+
$this->setSource(new PhabricatorConfigDictionarySource($config));
9+
}
10+
11+
public function setKeys(array $keys) {
12+
$result = parent::setKeys($keys);
13+
$this->saveConfig();
14+
return $result;
15+
}
16+
17+
public function deleteKeys(array $keys) {
18+
$result = parent::deleteKeys($keys);
19+
$this->saveConfig();
20+
return parent::deleteKeys($keys);
21+
}
22+
23+
private function loadConfig() {
24+
$path = $this->getConfigPath();
25+
if (@file_exists($path)) {
26+
$data = @file_get_contents($path);
27+
if ($data) {
28+
$data = json_decode($data, true);
29+
if (is_array($data)) {
30+
return $data;
31+
}
32+
}
33+
}
34+
35+
return array();
36+
}
37+
38+
private function saveConfig() {
39+
$config = $this->getSource()->getAllKeys();
40+
$json = new PhutilJSON();
41+
$data = $json->encodeFormatted($config);
42+
Filesystem::writeFile($this->getConfigPath(), $data);
43+
}
44+
45+
private function getConfigPath() {
46+
$root = dirname(phutil_get_library_root('phabricator'));
47+
$path = $root.'/conf/local/local.json';
48+
return $path;
49+
}
50+
51+
}

src/infrastructure/env/PhabricatorConfigProxySource.php

+3-3
Original file line numberDiff line numberDiff line change
@@ -29,15 +29,15 @@ public function getKeys(array $keys) {
2929
}
3030

3131
public function canWrite() {
32-
return $this->getSource->canWrite();
32+
return $this->getSource()->canWrite();
3333
}
3434

3535
public function setKeys(array $keys) {
36-
return $this->getSource->setKeys();
36+
return $this->getSource()->setKeys($keys);
3737
}
3838

3939
public function deleteKeys(array $keys) {
40-
return $this->getSource->deleteKeys();
40+
return $this->getSource()->deleteKeys();
4141
}
4242

4343
}

src/infrastructure/env/PhabricatorEnv.php

+8
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,14 @@ public static function getSelectedEnvironmentName() {
139139
$env = idx($_ENV, $env_var);
140140
}
141141

142+
if (!$env) {
143+
$root = dirname(phutil_get_library_root('phabricator'));
144+
$path = $root.'/conf/local/ENVIRONMENT';
145+
if (Filesystem::pathExists($path)) {
146+
$env = trim(Filesystem::readFile($path));
147+
}
148+
}
149+
142150
return $env;
143151
}
144152

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
<?php
2+
3+
final class PhabricatorConfigManagementSetWorkflow
4+
extends PhabricatorConfigManagementWorkflow {
5+
6+
protected function didConstruct() {
7+
$this
8+
->setName('set')
9+
->setExamples('**set** __key__ __value__')
10+
->setSynopsis('Set a local configuration value.')
11+
->setArguments(
12+
array(
13+
array(
14+
'name' => 'args',
15+
'wildcard' => true,
16+
),
17+
));
18+
}
19+
20+
public function execute(PhutilArgumentParser $args) {
21+
$console = PhutilConsole::getConsole();
22+
23+
$argv = $args->getArg('args');
24+
if (count($argv) == 0) {
25+
throw new PhutilArgumentUsageException(
26+
"Specify a configuration key and a value to set it to.");
27+
}
28+
29+
$key = $argv[0];
30+
31+
if (count($argv) == 1) {
32+
throw new PhutilArgumentUsageException(
33+
"Specify a value to set the key '{$key}' to.");
34+
}
35+
36+
$value = $argv[1];
37+
38+
if (count($argv) > 2) {
39+
throw new PhutilArgumentUsageException(
40+
"Too many arguments: expected one key and one value.");
41+
}
42+
43+
$config = new PhabricatorConfigLocalSource();
44+
$config->setKeys(array($key => $value));
45+
46+
$console->writeOut(
47+
pht("Set '%s' to '%s' in local configuration.", $key, $value)."\n");
48+
}
49+
50+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
<?php
2+
3+
abstract class PhabricatorConfigManagementWorkflow
4+
extends PhutilArgumentWorkflow {
5+
6+
final public function isExecutable() {
7+
return true;
8+
}
9+
10+
}

0 commit comments

Comments
 (0)