2011-04-08 01:55:32 +02:00
|
|
|
#!/usr/bin/env php
|
|
|
|
<?php
|
|
|
|
|
|
|
|
/*
|
2012-03-02 20:09:31 +01:00
|
|
|
* Copyright 2012 Facebook, Inc.
|
2011-04-08 01:55:32 +02:00
|
|
|
*
|
|
|
|
* 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.
|
|
|
|
*/
|
|
|
|
|
|
|
|
$root = dirname(dirname(dirname(__FILE__)));
|
|
|
|
require_once $root.'/scripts/__init_script__.php';
|
|
|
|
|
2011-04-14 18:41:43 +02:00
|
|
|
phutil_require_module('phutil', 'console');
|
2011-05-05 20:00:05 +02:00
|
|
|
phutil_require_module('phabricator', 'infrastructure/setup/sql');
|
2011-04-14 18:41:43 +02:00
|
|
|
|
2011-04-30 08:13:50 +02:00
|
|
|
define('SCHEMA_VERSION_TABLE_NAME', 'schema_version');
|
2011-04-08 01:55:32 +02:00
|
|
|
|
2011-06-01 04:08:58 +02:00
|
|
|
// TODO: getopt() is super terrible, move to something less terrible.
|
2012-03-02 20:09:31 +01:00
|
|
|
$options = getopt('fhdv:u:p:m:') + array(
|
2011-06-01 04:08:58 +02:00
|
|
|
'v' => null, // Upgrade from specific version
|
|
|
|
'u' => null, // Override MySQL User
|
|
|
|
'p' => null, // Override MySQL Pass
|
2012-03-02 20:09:31 +01:00
|
|
|
'm' => null, // Specify max version to upgrade to
|
2011-04-30 09:18:13 +02:00
|
|
|
);
|
|
|
|
|
2012-03-02 20:09:31 +01:00
|
|
|
foreach (array('h', 'f', 'd') as $key) {
|
2011-06-01 04:08:58 +02:00
|
|
|
// By default, these keys are set to 'false' to indicate that the flag was
|
|
|
|
// passed.
|
|
|
|
if (array_key_exists($key, $options)) {
|
|
|
|
$options[$key] = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-03-02 20:09:31 +01:00
|
|
|
if (!empty($options['h']) || ($options['v'] && !is_numeric($options['v']))
|
|
|
|
|| ($options['m'] && !is_numeric($options['m']))) {
|
2011-04-30 09:18:13 +02:00
|
|
|
usage();
|
2011-04-08 01:55:32 +02:00
|
|
|
}
|
|
|
|
|
2012-03-02 20:09:31 +01:00
|
|
|
if (empty($options['f']) && empty($options['d'])) {
|
2011-06-01 04:08:58 +02:00
|
|
|
echo phutil_console_wrap(
|
|
|
|
"Before running this script, you should take down the Phabricator web ".
|
|
|
|
"interface and stop any running Phabricator daemons.");
|
2011-04-14 18:41:43 +02:00
|
|
|
|
2011-06-01 04:08:58 +02:00
|
|
|
if (!phutil_console_confirm('Are you ready to continue?')) {
|
|
|
|
echo "Cancelled.\n";
|
|
|
|
exit(1);
|
|
|
|
}
|
2011-04-14 18:41:43 +02:00
|
|
|
}
|
|
|
|
|
2011-04-08 01:55:32 +02:00
|
|
|
// Use always the version from the commandline if it is defined
|
2011-04-30 09:18:13 +02:00
|
|
|
$next_version = isset($options['v']) ? (int)$options['v'] : null;
|
2012-03-02 20:09:31 +01:00
|
|
|
$max_version = isset($options['m']) ? (int)$options['m'] : null;
|
2011-04-30 09:18:13 +02:00
|
|
|
|
2011-06-12 00:11:50 +02:00
|
|
|
$conf = DatabaseConfigurationProvider::getConfiguration();
|
|
|
|
|
2011-04-30 09:18:13 +02:00
|
|
|
if ($options['u']) {
|
|
|
|
$conn_user = $options['u'];
|
|
|
|
$conn_pass = $options['p'];
|
|
|
|
} else {
|
2011-06-12 00:11:50 +02:00
|
|
|
$conn_user = $conf->getUser();
|
|
|
|
$conn_pass = $conf->getPassword();
|
2011-04-08 01:55:32 +02:00
|
|
|
}
|
2011-06-12 00:11:50 +02:00
|
|
|
$conn_host = $conf->getHost();
|
2011-04-08 01:55:32 +02:00
|
|
|
|
2011-06-08 19:10:11 +02:00
|
|
|
// Split out port information, since the command-line client requires a
|
|
|
|
// separate flag for the port.
|
|
|
|
$uri = new PhutilURI('mysql://'.$conn_host);
|
|
|
|
if ($uri->getPort()) {
|
|
|
|
$conn_port = $uri->getPort();
|
|
|
|
$conn_bare_hostname = $uri->getDomain();
|
|
|
|
} else {
|
|
|
|
$conn_port = null;
|
|
|
|
$conn_bare_hostname = $conn_host;
|
|
|
|
}
|
|
|
|
|
2011-04-30 09:18:13 +02:00
|
|
|
$conn = new AphrontMySQLDatabaseConnection(
|
|
|
|
array(
|
|
|
|
'user' => $conn_user,
|
|
|
|
'pass' => $conn_pass,
|
|
|
|
'host' => $conn_host,
|
|
|
|
'database' => null,
|
|
|
|
));
|
|
|
|
|
|
|
|
try {
|
2011-04-08 01:55:32 +02:00
|
|
|
|
2011-04-30 09:18:13 +02:00
|
|
|
$create_sql = <<<END
|
|
|
|
CREATE DATABASE IF NOT EXISTS `phabricator_meta_data`;
|
2011-04-08 01:55:32 +02:00
|
|
|
END;
|
2011-04-30 09:18:13 +02:00
|
|
|
queryfx($conn, $create_sql);
|
2011-04-08 01:55:32 +02:00
|
|
|
|
2011-04-30 09:18:13 +02:00
|
|
|
$create_sql = <<<END
|
|
|
|
CREATE TABLE IF NOT EXISTS phabricator_meta_data.`schema_version` (
|
|
|
|
`version` INTEGER not null
|
|
|
|
);
|
2011-04-08 01:55:32 +02:00
|
|
|
END;
|
2011-04-30 09:18:13 +02:00
|
|
|
queryfx($conn, $create_sql);
|
|
|
|
|
|
|
|
// Get the version only if commandline argument wasn't given
|
|
|
|
if ($next_version === null) {
|
|
|
|
$version = queryfx_one(
|
|
|
|
$conn,
|
|
|
|
'SELECT * FROM phabricator_meta_data.%T',
|
|
|
|
SCHEMA_VERSION_TABLE_NAME);
|
|
|
|
|
|
|
|
if (!$version) {
|
|
|
|
print "*** No version information in the database ***\n";
|
|
|
|
print "*** Give the first patch version which to ***\n";
|
|
|
|
print "*** apply as the command line argument ***\n";
|
|
|
|
exit(-1);
|
|
|
|
}
|
|
|
|
|
|
|
|
$next_version = $version['version'] + 1;
|
2011-04-08 01:55:32 +02:00
|
|
|
}
|
|
|
|
|
2011-05-05 20:00:05 +02:00
|
|
|
$patches = PhabricatorSQLPatchList::getPatchList();
|
2011-04-30 09:18:13 +02:00
|
|
|
|
|
|
|
$patch_applied = false;
|
|
|
|
foreach ($patches as $patch) {
|
|
|
|
if ($patch['version'] < $next_version) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2012-03-02 20:09:31 +01:00
|
|
|
if ($max_version && $patch['version'] > $max_version) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2011-05-05 20:00:05 +02:00
|
|
|
$short_name = basename($patch['path']);
|
|
|
|
print "Applying patch {$short_name}...\n";
|
2011-04-30 09:18:13 +02:00
|
|
|
|
2012-03-02 20:09:31 +01:00
|
|
|
if (!empty($options['d'])) {
|
|
|
|
$patch_applied = true;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2011-06-08 19:10:11 +02:00
|
|
|
if ($conn_port) {
|
|
|
|
$port = '--port='.(int)$conn_port;
|
|
|
|
} else {
|
|
|
|
$port = null;
|
|
|
|
}
|
|
|
|
|
2011-07-11 19:46:54 +02:00
|
|
|
if (preg_match('/\.php$/', $patch['path'])) {
|
|
|
|
$schema_conn = $conn;
|
|
|
|
require_once $patch['path'];
|
|
|
|
} else {
|
|
|
|
list($stdout, $stderr) = execx(
|
2012-03-08 19:57:03 +01:00
|
|
|
"mysql --user=%s --password=%s --host=%s {$port} ".
|
|
|
|
"--default-character-set=utf8 < %s",
|
2011-07-11 19:46:54 +02:00
|
|
|
$conn_user,
|
|
|
|
$conn_pass,
|
|
|
|
$conn_bare_hostname,
|
|
|
|
$patch['path']);
|
|
|
|
|
|
|
|
if ($stderr) {
|
|
|
|
print $stderr;
|
|
|
|
exit(-1);
|
|
|
|
}
|
2011-04-30 09:18:13 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
// Patch was successful, update the db with the latest applied patch version
|
|
|
|
// 'DELETE' and 'INSERT' instead of update, because the table might be empty
|
|
|
|
queryfx(
|
|
|
|
$conn,
|
|
|
|
'DELETE FROM phabricator_meta_data.%T',
|
|
|
|
SCHEMA_VERSION_TABLE_NAME);
|
|
|
|
queryfx(
|
|
|
|
$conn,
|
|
|
|
'INSERT INTO phabricator_meta_data.%T VALUES (%d)',
|
|
|
|
SCHEMA_VERSION_TABLE_NAME,
|
|
|
|
$patch['version']);
|
|
|
|
|
|
|
|
$patch_applied = true;
|
2011-04-08 01:55:32 +02:00
|
|
|
}
|
|
|
|
|
2011-04-30 09:18:13 +02:00
|
|
|
if (!$patch_applied) {
|
|
|
|
print "Your database is already up-to-date.\n";
|
2011-04-08 01:55:32 +02:00
|
|
|
}
|
|
|
|
|
2011-04-30 09:18:13 +02:00
|
|
|
} catch (AphrontQueryAccessDeniedException $ex) {
|
|
|
|
echo
|
|
|
|
"ACCESS DENIED\n".
|
|
|
|
"The user '{$conn_user}' does not have sufficient MySQL privileges to\n".
|
|
|
|
"execute the schema upgrade. Use the -u and -p flags to run as a user\n".
|
|
|
|
"with more privileges (e.g., root).".
|
|
|
|
"\n\n".
|
|
|
|
"EXCEPTION:\n".
|
|
|
|
$ex->getMessage().
|
|
|
|
"\n\n";
|
|
|
|
exit(1);
|
2011-04-08 01:55:32 +02:00
|
|
|
}
|
|
|
|
|
2011-04-30 09:18:13 +02:00
|
|
|
function usage() {
|
|
|
|
echo
|
2011-06-01 04:08:58 +02:00
|
|
|
"usage: upgrade_schema.php [-v version] [-u user -p pass] [-f] [-h]".
|
2011-04-30 09:18:13 +02:00
|
|
|
"\n\n".
|
|
|
|
"Run 'upgrade_schema.php -u root -p hunter2' to override the configured ".
|
2011-06-01 04:08:58 +02:00
|
|
|
"default user.\n".
|
|
|
|
"Run 'upgrade_schema.php -v 12' to apply all patches starting from ".
|
|
|
|
"version 12. It is very unlikely you need to do this.\n".
|
2012-03-02 20:09:31 +01:00
|
|
|
"Run 'upgrade_schema.php -m 110' to apply all patches up to and ".
|
|
|
|
"including version 110 (but nothing past).\n".
|
2011-06-01 04:08:58 +02:00
|
|
|
"Use the -f flag to upgrade noninteractively, without prompting.\n".
|
2012-03-02 20:09:31 +01:00
|
|
|
"Use the -d flag to do a dry run - patches that would be applied ".
|
|
|
|
"will be listed, but not applied.\n".
|
2011-06-01 04:08:58 +02:00
|
|
|
"Use the -h flag to show this help.\n";
|
2011-04-30 09:18:13 +02:00
|
|
|
exit(1);
|
2011-04-08 01:55:32 +02:00
|
|
|
}
|
2011-04-30 09:18:13 +02:00
|
|
|
|