1
0
Fork 0
mirror of https://we.phorge.it/source/phorge.git synced 2024-11-09 16:32:39 +01:00

Add a "setup" mode which guides new users through application configuration

Summary:
Alters the installation instructions to guide installers into a "setup" mode
which does config file sanity checking.

Test Plan:
Put myself in setup mode, simulated all the failures it detects, took myself out
of setup mode, Phabricator works OK.

Reviewed By: tuomaspelkonen
Reviewers: jungejason, tuomaspelkonen, aran
CC: aran, tuomaspelkonen, epriestley
Differential Revision: 230
This commit is contained in:
epriestley 2011-05-05 11:00:05 -07:00
parent 90364cafdc
commit f7e2b03077
13 changed files with 461 additions and 100 deletions

View file

@ -27,6 +27,10 @@ return array(
// contain the right links.
'phabricator.production-uri' => null,
// Setting this to 'true' will invoke a special setup mode which helps guide
// you through setting up Phabricator.
'phabricator.setup' => false,
// The default PHID for users who haven't uploaded a profile image. It should
// be 50x50px.
'user.default-profile-image-phid' => 'PHID-FILE-4d61229816cfe6f2b2a3',
@ -78,7 +82,7 @@ return array(
// some data like queries and stack traces, so you should be careful about
// turning it on in production (although users can not normally see it, even
// if the deployment configuration enables it).
'darkconsole.enabled' => true,
'darkconsole.enabled' => false,
// Always enable DarkConsole, even for logged out users. This potentially
// exposes sensitive information to users, so make sure untrusted users can

View file

@ -18,5 +18,6 @@
return array(
'darkconsole.enabled' => true,
) + phabricator_read_config_file('default');

View file

@ -18,7 +18,5 @@
return array(
'darkconsole.enabled' => false,
) + phabricator_read_config_file('default');

View file

@ -1,22 +0,0 @@
<?php
/*
* Copyright 2011 Facebook, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
return array(
) + phabricator_read_config_file('default');

View file

@ -0,0 +1 @@
SELECT 1;

View file

@ -22,6 +22,7 @@ require_once $root.'/scripts/__init_script__.php';
require_once $root.'/scripts/__init_env__.php';
phutil_require_module('phutil', 'console');
phutil_require_module('phabricator', 'infrastructure/setup/sql');
define('SCHEMA_VERSION_TABLE_NAME', 'schema_version');
@ -95,28 +96,7 @@ END;
$next_version = $version['version'] + 1;
}
// Find the patch files
$patches_dir = $root.'/resources/sql/patches/';
$finder = id(new FileFinder($patches_dir))
->withSuffix('sql');
$results = $finder->find();
$patches = array();
foreach ($results as $r) {
$matches = array();
if (preg_match('/(\d+)\..*\.sql$/', $r, $matches)) {
$patches[] = array('version' => (int)$matches[1],
'file' => $r);
} else {
print
"*** WARNING : File {$r} does not follow the normal naming ".
"convention. ***\n";
}
}
// Files are in some 'random' order returned by the operating system
// We need to apply them in proper order
$patches = isort($patches, 'version');
$patches = PhabricatorSQLPatchList::getPatchList();
$patch_applied = false;
foreach ($patches as $patch) {
@ -124,16 +104,15 @@ END;
continue;
}
print "Applying patch {$patch['file']}\n";
$path = Filesystem::resolvePath($patches_dir.$patch['file']);
$short_name = basename($patch['path']);
print "Applying patch {$short_name}...\n";
list($stdout, $stderr) = execx(
"mysql --user=%s --password=%s --host=%s < %s",
$conn_user,
$conn_pass,
$conn_host,
$path);
$patch['path']);
if ($stderr) {
print $stderr;

View file

@ -425,6 +425,7 @@ phutil_register_library_map(array(
'PhabricatorRepositorySvnCommitDiscoveryDaemon' => 'applications/repository/daemon/commitdiscovery/svn',
'PhabricatorRepositorySvnCommitMessageParserWorker' => 'applications/repository/worker/commitmessageparser/svn',
'PhabricatorRepositoryType' => 'applications/repository/constants/repositorytype',
'PhabricatorSQLPatchList' => 'infrastructure/setup/sql',
'PhabricatorSearchAbstractDocument' => 'applications/search/index/abstractdocument',
'PhabricatorSearchBaseController' => 'applications/search/controller/base',
'PhabricatorSearchController' => 'applications/search/controller/search',
@ -440,6 +441,7 @@ phutil_register_library_map(array(
'PhabricatorSearchMySQLExecutor' => 'applications/search/execute/mysql',
'PhabricatorSearchQuery' => 'applications/search/storage/query',
'PhabricatorSearchRelationship' => 'applications/search/constants/relationship',
'PhabricatorSetup' => 'infrastructure/setup',
'PhabricatorStandardPageView' => 'view/page/standard',
'PhabricatorStatusController' => 'applications/status/base',
'PhabricatorTaskmasterDaemon' => 'infrastructure/daemon/workers/taskmaster',

View file

@ -16,9 +16,32 @@ schemata into it. First, load the initial database schema.
mysql -uroot < path/to/phabricator/resources/sql/init/initialize.sql
After this you need to upgrade the schema see @{article:Upgrading Schema},
After this you need to upgrade the schema (see @{article:Upgrading Schema}),
but you need to finish the rest of the configuration first.
= Configuring Phabricator =
Create a new file here:
path/to/phabricator/conf/custom/myconfig.conf.php
...where ##myconfig## is some name which identifies your installation. Put this
in the file:
<?php
return array(
// Important! This will put Phabricator into setup mode to help you
// configure things.
'phabricator.setup' => true,
) + phabricator_read_config_file('production');
For the last line, you can also use ##'development'## instead of
##'production'## if you are planning to develop Phabricator itself. This will
turn on some debugging features.
= Configuring Apache =
Get Apache running and verify it's serving a test page. Consult the Apache
@ -49,27 +72,38 @@ this:
RewriteRule ^/favicon.ico - [L,QSA]
RewriteRule ^(.*)$ /index.php?__path__=$1 [L,QSA]
# This will use "setup" defaults for configuration options, which will
# expose error messages. Before you make the install public, you should
# change this to "production" and/or customize your configuration. See
# the next section for details.
SetEnv PHABRICATOR_ENV setup
# This will use the config file you set up in the previous step. If you
# called it something other than 'myconfig', put that here.
SetEnv PHABRICATOR_ENV custom/myconfig
</VirtualHost>
Now, restart apache and navigate to whichever subdomain you set up. You should
either see the Phabricator login screen, which means you're all set, or some
useful error message telling you what else you need to fix (for instance, you
may need to set up MySQL credentials). If you see something else, you did
something very wrong and/or this document lied to you.
either see the Phabricator setup screen, which is a simple text page that looks
something like this:
PHABRICATOR SETUP
This setup mode will guide you through setting up your Phabricator
configuration.
>>> REQUIRED PHP EXTENSIONS ------------------------------------------------
...
If you see this, you're in good shape. Follow the instructions and correct any
problems setup detects. If you don't see it but you do see a useful error
message, try to fix that. If neither of these cover you, something is wrong.
If you can't figure it out, come get help in IRC or on the mailing list (see
http://phabricator.org/ for links).
= Configuring Phabricator =
Now that basic setup is complete, you should configure Phabricator. Phabricator
configuration options which control how the applications behave are stored here:
Now that basic setup is complete, you should configure Phabricator for your
installation. Phabricator configuration options which control how the
applications behave are documented here:
/path/to/phabricator/conf/
/path/to/phabricator/conf/default.conf.php
There are several configuration templates:
There are several builtin configurations:
- ##default.conf.php##: root configuration, lists every configuration option
and sets some default for it. Look in this file to figure out what you can
@ -80,44 +114,14 @@ There are several configuration templates:
changes to Phabricator itself.
- ##production.conf.php##: pulls in ##default.conf.php##, but overrides some
configuration options to provide better values for a production install.
Once you've completed setup, you should switch to this configuration or
one based upon it.
- ##setup.conf.php##: pulls in ##default.conf.php##, but sets some flags that
make it easier to set up a Phabricator install. Switch away from this before
deploying a production install.
While you can use these templates as-is, you'll probably want to set up custom
configuration. To do this, create a new file:
/path/to/phabricator/conf/custom/myconfig.conf.php
Put this in the file:
<?php
return array(
// This is just an example.
'some.config' => 'some_value',
) + phabricator_read_config_file('production');
This will create a new config called "custom/myconfig" which uses the
"production" config as the default but allows you to override options. You can
select it by editing the VirtualHost or Directory entry you set up when
configuring Apache:
<VirtualHost *>
# ...
SetEnv PHABRICATOR_ENV custom/myconfig
# ...
</VirtualHost>
Now, look through ##default.conf.php## and override any options you want to
change by providing overrides in ##myconfig.conf.php##.
To actually configure your install, edit your ##custom/myconfig.conf.php## file
and override values from either the ##'production'## or ##'development'##
configurations. You should not edit the builtin configurations directly because
that will make upgrading Phabricator more difficult in the future.
= Upgrading Schema =
After you have configured Phabricator, you need to upgrade the database
schema, see @{article:Upgrading Schema}. You'll also need to do this after you
schema -- see @{article:Upgrading Schema}. You'll also need to do this after you
update the code in the future.

View file

@ -0,0 +1,298 @@
<?php
/*
* Copyright 2011 Facebook, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
class PhabricatorSetup {
const EXPECTED_SCHEMA_VERSION = 36;
public static function runSetup() {
header("Content-Type: text/plain");
self::write("PHABRICATOR SETUP\n\n");
// Force browser to stop buffering.
self::write(str_repeat(' ', 2048));
usleep(250000);
self::write("This setup mode will guide you through setting up your ".
"Phabricator configuration.\n");
self::writeHeader("REQUIRED PHP EXTENSIONS");
$extensions = array(
'mysql',
'hash',
'json',
);
foreach ($extensions as $extension) {
$ok = self::requireExtension($extension);
if (!$ok) {
self::writeFailure();
self::write("Setup failure! Install PHP extension '{$extension}'.");
return;
}
}
self::write("[OKAY] All extensions OKAY\n\n");
self::writeHeader("GIT SUBMODULES");
$root = dirname(phutil_get_library_root('phabricator'));
if (!Filesystem::pathExists($root.'/.git')) {
self::write(" skip Not a git clone.\n\n");
} else {
list($info) = execx(
'(cd %s && git submodule status)',
$root);
foreach (explode("\n", rtrim($info)) as $line) {
$matches = null;
if (!preg_match('/^(.)([0-9a-f]{40}) (\S+)(?: |$)/', $line, $matches)) {
self::writeFailure();
self::write(
"Setup failure! 'git submodule' produced unexpected output:\n".
$line);
return;
}
$status = $matches[1];
$module = $matches[3];
switch ($status) {
case '-':
case '+':
case 'U':
self::writeFailure();
self::write(
"Setup failure! Git submodule '{$module}' is not up to date. ".
"Run:\n\n".
" cd {$root} && git submodule update --init\n\n".
"...to update submodules.");
return;
case ' ':
self::write(" okay Git submodule '{$module}' up to date.\n");
break;
default:
self::writeFailure();
self::write(
"Setup failure! 'git submodule' reported unknown status ".
"'{$status}' for submodule '{$module}'. This is a bug; report ".
"it to the Phabricator maintainers.");
return;
}
}
}
self::write("[OKAY] All submodules OKAY.");
self::writeHeader("BASIC CONFIGURATION");
$env = PhabricatorEnv::getEnvConfig('phabricator.env');
if ($env == 'production' || $env == 'default' || $env == 'development') {
self::writeFailure();
self::write(
"Setup failure! Your PHABRICATOR_ENV is set to '{$env}', which is ".
"a Phabricator environmental default. You should create a custom ".
"environmental configuration instead of editing the defaults ".
"directly. See this document for instructions:\n");
self::writeDoc('article/Configuration_Guide.html');
return;
} else {
self::write(" okay Custom configuration loaded.\n");
}
if (!PhabricatorEnv::getEnvConfig('phabricator.base-uri')) {
self::writeFailure();
self::write(
"Setup failure! You must specify 'phabricator.base-uri' in your ".
"custom config file. Refer to 'default.conf.php' for documentation ".
"on configuration options.\n");
return;
} else {
self::write(" okay phabricator.base-uri\n");
}
self::write("[OKAY] Basic configuration OKAY\n");
self::writeHeader('FACEBOOK INTEGRATION');
$fb_auth = PhabricatorEnv::getEnvConfig('facebook.auth-enabled');
if (!$fb_auth) {
self::write(" skip 'facebook.auth-enabled' not enabled.\n");
} else {
self::write(" okay 'facebook.auth-enabled' is enabled.\n");
$app_id = PhabricatorEnv::getEnvConfig('facebook.application-id');
$app_secret = PhabricatorEnv::getEnvConfig('facebook.application-secret');
if (!$app_id) {
self::writeFailure();
self::write(
"Setup failure! 'facebook.auth-enabled' is true but there is no ".
"setting for 'facebook.application-id'.\n");
return;
} else {
self::write(" okay 'facebook.application-id' is set.\n");
}
if (!is_string($app_id)) {
self::writeFailure();
self::write(
"Setup failure! 'facebook.application-id' should be a string.");
return;
} else {
self::write(" okay 'facebook.application-id' is string.\n");
}
if (!$app_secret) {
self::writeFailure();
self::write(
"Setup failure! 'facebook.auth-enabled' is true but there is no ".
"setting for 'facebook.application-secret'.");
return;
} else {
self::write(" okay 'facebook.application-secret is set.\n");
}
self::write("[OKAY] Facebook integration OKAY\n");
}
self::writeHeader("MySQL DATABASE CONFIGURATION");
$conn_user = PhabricatorEnv::getEnvConfig('mysql.user');
$conn_pass = PhabricatorEnv::getEnvConfig('mysql.pass');
$conn_host = PhabricatorEnv::getEnvConfig('mysql.host');
$timeout = ini_get('mysql.connect_timeout');
if ($timeout > 5) {
self::writeNote(
"Your MySQL connect timeout is very high ({$timeout} seconds). ".
"Consider reducing it by setting 'mysql.connect_timeout' in your ".
"php.ini.");
}
self::write(" okay Trying to connect to MySQL database ".
"{$conn_user}@{$conn_host}...\n");
ini_set('mysql.connect_timeout', 2);
$conn_raw = new AphrontMySQLDatabaseConnection(
array(
'user' => $conn_user,
'pass' => $conn_pass,
'host' => $conn_host,
'database' => null,
));
try {
queryfx($conn_raw, 'SELECT 1');
self::write(" okay Connection successful!\n");
} catch (AphrontQueryConnectionException $ex) {
self::writeFailure();
self::write(
"Setup failure! Unable to connect to MySQL database ".
"'{$conn_host}' with user '{$conn_user}'. Edit Phabricator ".
"configuration keys 'mysql.user', 'mysql.host' and 'mysql.pass' to ".
"enable Phabricator to connect.");
return;
}
$databases = queryfx_all($conn_raw, 'SHOW DATABASES');
$databases = ipull($databases, 'Database');
$databases = array_fill_keys($databases, true);
if (empty($databases['phabricator_meta_data'])) {
self::writeFailure();
self::write(
"Setup failure! You haven't loaded the 'initialize.sql' file into ".
"MySQL. This file initializes necessary databases. See this guide for ".
"instructions:\n");
self::writeDoc('article/Configuration_Guide.html');
return;
} else {
self::write(" okay Databases have been initialized.\n");
}
$schema_version = queryfx_one(
$conn_raw,
'SELECT version FROM phabricator_meta_data.schema_version');
$schema_version = idx($schema_version, 'version', 'null');
$expect = PhabricatorSQLPatchList::getExpectedSchemaVersion();
if ($schema_version != $expect) {
self::writeFailure();
self::write(
"Setup failure! You haven't upgraded your database schema to the ".
"latest version. Expected version is '{$expect}', but your local ".
"version is '{$schema_version}'. See this guide for instructions:\n");
self::writeDoc('article/Upgrading_Schema.html');
return;
} else {
self::write(" okay Database schema are up to date (v{$expect}).\n");
}
self::write("[OKAY] Database configuration OKAY\n");
self::writeHeader('SUCCESS!');
self::write(
"Congratulations! Your setup seems mostly correct, or at least fairly ".
"reasonable.\n\n".
"*** NEXT STEP ***\n".
"Edit your configuration file (conf/{$env}.conf.php) and remove the ".
"'phabricator.setup' line to finish installation.");
}
public static function requireExtension($extension) {
if (extension_loaded($extension)) {
self::write(" okay Extension '{$extension}' installed.\n");
return true;
} else {
self::write("[FAIL] Extension '{$extension}' is NOT INSTALLED!\n");
return false;
}
}
private static function writeFailure() {
self::write("\n\n<<< *** FAILURE! *** >>>\n");
}
private static function write($str) {
echo $str;
ob_flush();
flush();
// This, uh, makes it look cool. -_-
usleep(40000);
}
private static function writeNote($note) {
self::write(
'Note: '.wordwrap($note, 75, "\n ", true)."\n\n");
}
public static function writeHeader($header) {
$template = '>>>'.str_repeat('-', 77);
$template = substr_replace(
$template,
' '.$header.' ',
3,
strlen($header) + 4);
self::write("\n\n{$template}\n\n");
}
public static function writeDoc($doc) {
self::write(
"\n".
' http://phabricator.com/docs/phabricator/'.$doc.
"\n\n");
}
}

View file

@ -0,0 +1,20 @@
<?php
/**
* This file is automatically generated. Lint this module to rebuild it.
* @generated
*/
phutil_require_module('phabricator', 'infrastructure/env');
phutil_require_module('phabricator', 'infrastructure/setup/sql');
phutil_require_module('phabricator', 'storage/connection/mysql');
phutil_require_module('phabricator', 'storage/queryfx');
phutil_require_module('phutil', 'filesystem');
phutil_require_module('phutil', 'future/exec');
phutil_require_module('phutil', 'moduleutils');
phutil_require_module('phutil', 'utils');
phutil_require_source('PhabricatorSetup.php');

View file

@ -0,0 +1,57 @@
<?php
/*
* Copyright 2011 Facebook, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
final class PhabricatorSQLPatchList {
public static function getPatchList() {
$root = dirname(phutil_get_library_root('phabricator'));
// Find the patch files
$patches_dir = $root.'/resources/sql/patches/';
$finder = id(new FileFinder($patches_dir))
->withSuffix('sql');
$results = $finder->find();
$patches = array();
foreach ($results as $path) {
$matches = array();
if (preg_match('/(\d+)\..*\.sql$/', $path, $matches)) {
$patches[] = array(
'version' => (int)$matches[1],
'path' => $patches_dir.$path,
);
} else {
throw new Exception("Patch file '{$path}' is not properly named.");
}
}
// Files are in some 'random' order returned by the operating system
// We need to apply them in proper order
$patches = isort($patches, 'version');
return $patches;
}
public static function getExpectedSchemaVersion() {
$patches = self::getPatchList();
$versions = ipull($patches, 'version');
$max_version = max($versions);
return $max_version;
}
}

View file

@ -0,0 +1,14 @@
<?php
/**
* This file is automatically generated. Lint this module to rebuild it.
* @generated
*/
phutil_require_module('phutil', 'filesystem/filefinder');
phutil_require_module('phutil', 'moduleutils');
phutil_require_module('phutil', 'utils');
phutil_require_source('PhabricatorSQLPatchList.php');

View file

@ -89,6 +89,11 @@ foreach (PhabricatorEnv::getEnvConfig('load-libraries') as $library) {
phutil_load_library($library);
}
if (PhabricatorEnv::getEnvConfig('phabricator.setup')) {
PhabricatorSetup::runSetup();
return;
}
$host = $_SERVER['HTTP_HOST'];
$path = $_REQUEST['__path__'];