| 
									
										
										
										
											2011-04-07 16:55:32 -07:00
										 |  |  | #!/usr/bin/env php
 | 
					
						
							|  |  |  | <?php | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* | 
					
						
							| 
									
										
										
										
											2012-03-02 11:09:31 -08:00
										 |  |  |  * Copyright 2012 Facebook, Inc. | 
					
						
							| 
									
										
										
										
											2011-04-07 16:55:32 -07: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 09:41:43 -07:00
										 |  |  | phutil_require_module('phutil', 'console'); | 
					
						
							| 
									
										
										
										
											2011-05-05 11:00:05 -07:00
										 |  |  | phutil_require_module('phabricator', 'infrastructure/setup/sql'); | 
					
						
							| 
									
										
										
										
											2011-04-14 09:41:43 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-04-29 23:13:50 -07:00
										 |  |  | define('SCHEMA_VERSION_TABLE_NAME', 'schema_version'); | 
					
						
							| 
									
										
										
										
											2011-04-07 16:55:32 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-05-31 19:08:58 -07:00
										 |  |  | // TODO: getopt() is super terrible, move to something less terrible.
 | 
					
						
							| 
									
										
										
										
											2012-03-02 11:09:31 -08:00
										 |  |  | $options = getopt('fhdv:u:p:m:') + array( | 
					
						
							| 
									
										
										
										
											2011-05-31 19:08:58 -07:00
										 |  |  |   'v' => null, // Upgrade from specific version
 | 
					
						
							|  |  |  |   'u' => null, // Override MySQL User
 | 
					
						
							|  |  |  |   'p' => null, // Override MySQL Pass
 | 
					
						
							| 
									
										
										
										
											2012-03-02 11:09:31 -08:00
										 |  |  |   'm' => null, // Specify max version to upgrade to
 | 
					
						
							| 
									
										
										
										
											2011-04-30 00:18:13 -07:00
										 |  |  | ); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-03-02 11:09:31 -08:00
										 |  |  | foreach (array('h', 'f', 'd') as $key) { | 
					
						
							| 
									
										
										
										
											2011-05-31 19:08:58 -07: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 11:09:31 -08:00
										 |  |  | if (!empty($options['h']) || ($options['v'] && !is_numeric($options['v'])) | 
					
						
							|  |  |  |     || ($options['m'] && !is_numeric($options['m']))) { | 
					
						
							| 
									
										
										
										
											2011-04-30 00:18:13 -07:00
										 |  |  |   usage(); | 
					
						
							| 
									
										
										
										
											2011-04-07 16:55:32 -07:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-03-02 11:09:31 -08:00
										 |  |  | if (empty($options['f']) && empty($options['d'])) { | 
					
						
							| 
									
										
										
										
											2011-05-31 19:08:58 -07: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 09:41:43 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-05-31 19:08:58 -07:00
										 |  |  |   if (!phutil_console_confirm('Are you ready to continue?')) { | 
					
						
							|  |  |  |     echo "Cancelled.\n"; | 
					
						
							|  |  |  |     exit(1); | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2011-04-14 09:41:43 -07:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-04-07 16:55:32 -07:00
										 |  |  | // Use always the version from the commandline if it is defined
 | 
					
						
							| 
									
										
										
										
											2011-04-30 00:18:13 -07:00
										 |  |  | $next_version = isset($options['v']) ? (int)$options['v'] : null; | 
					
						
							| 
									
										
										
										
											2012-03-02 11:09:31 -08:00
										 |  |  | $max_version = isset($options['m']) ? (int)$options['m'] : null; | 
					
						
							| 
									
										
										
										
											2011-04-30 00:18:13 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-06-11 15:11:50 -07:00
										 |  |  | $conf = DatabaseConfigurationProvider::getConfiguration(); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-04-30 00:18:13 -07:00
										 |  |  | if ($options['u']) { | 
					
						
							|  |  |  |   $conn_user = $options['u']; | 
					
						
							|  |  |  |   $conn_pass = $options['p']; | 
					
						
							|  |  |  | } else { | 
					
						
							| 
									
										
										
										
											2011-06-11 15:11:50 -07:00
										 |  |  |   $conn_user = $conf->getUser(); | 
					
						
							|  |  |  |   $conn_pass = $conf->getPassword(); | 
					
						
							| 
									
										
										
										
											2011-04-07 16:55:32 -07:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2011-06-11 15:11:50 -07:00
										 |  |  | $conn_host = $conf->getHost(); | 
					
						
							| 
									
										
										
										
											2011-04-07 16:55:32 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-06-08 10:10:11 -07: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 00:18:13 -07:00
										 |  |  | $conn = new AphrontMySQLDatabaseConnection( | 
					
						
							|  |  |  |   array( | 
					
						
							|  |  |  |     'user'      => $conn_user, | 
					
						
							|  |  |  |     'pass'      => $conn_pass, | 
					
						
							|  |  |  |     'host'      => $conn_host, | 
					
						
							|  |  |  |     'database'  => null, | 
					
						
							|  |  |  |   )); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | try { | 
					
						
							| 
									
										
										
										
											2011-04-07 16:55:32 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-04-30 00:18:13 -07:00
										 |  |  |   $create_sql = <<<END | 
					
						
							|  |  |  |   CREATE DATABASE IF NOT EXISTS `phabricator_meta_data`; | 
					
						
							| 
									
										
										
										
											2011-04-07 16:55:32 -07:00
										 |  |  | END; | 
					
						
							| 
									
										
										
										
											2011-04-30 00:18:13 -07:00
										 |  |  |   queryfx($conn, $create_sql); | 
					
						
							| 
									
										
										
										
											2011-04-07 16:55:32 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-04-30 00:18:13 -07:00
										 |  |  |   $create_sql = <<<END | 
					
						
							|  |  |  |   CREATE TABLE IF NOT EXISTS phabricator_meta_data.`schema_version` ( | 
					
						
							|  |  |  |     `version` INTEGER not null | 
					
						
							|  |  |  |   ); | 
					
						
							| 
									
										
										
										
											2011-04-07 16:55:32 -07:00
										 |  |  | END; | 
					
						
							| 
									
										
										
										
											2011-04-30 00:18:13 -07: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-07 16:55:32 -07:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-05-05 11:00:05 -07:00
										 |  |  |   $patches = PhabricatorSQLPatchList::getPatchList(); | 
					
						
							| 
									
										
										
										
											2011-04-30 00:18:13 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |   $patch_applied = false; | 
					
						
							|  |  |  |   foreach ($patches as $patch) { | 
					
						
							|  |  |  |     if ($patch['version'] < $next_version) { | 
					
						
							|  |  |  |       continue; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-03-02 11:09:31 -08:00
										 |  |  |     if ($max_version && $patch['version'] > $max_version) { | 
					
						
							|  |  |  |       continue; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-05-05 11:00:05 -07:00
										 |  |  |     $short_name = basename($patch['path']); | 
					
						
							|  |  |  |     print "Applying patch {$short_name}...\n"; | 
					
						
							| 
									
										
										
										
											2011-04-30 00:18:13 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-03-02 11:09:31 -08:00
										 |  |  |     if (!empty($options['d'])) { | 
					
						
							|  |  |  |       $patch_applied = true; | 
					
						
							|  |  |  |       continue; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-06-08 10:10:11 -07:00
										 |  |  |     if ($conn_port) { | 
					
						
							|  |  |  |       $port = '--port='.(int)$conn_port; | 
					
						
							|  |  |  |     } else { | 
					
						
							|  |  |  |       $port = null; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-07-11 10:46:54 -07:00
										 |  |  |     if (preg_match('/\.php$/', $patch['path'])) { | 
					
						
							|  |  |  |       $schema_conn = $conn; | 
					
						
							|  |  |  |       require_once $patch['path']; | 
					
						
							|  |  |  |     } else { | 
					
						
							|  |  |  |       list($stdout, $stderr) = execx( | 
					
						
							| 
									
										
										
										
											2012-03-08 10:57:03 -08:00
										 |  |  |         "mysql --user=%s --password=%s --host=%s {$port} ". | 
					
						
							|  |  |  |         "--default-character-set=utf8 < %s", | 
					
						
							| 
									
										
										
										
											2011-07-11 10:46:54 -07:00
										 |  |  |         $conn_user, | 
					
						
							|  |  |  |         $conn_pass, | 
					
						
							|  |  |  |         $conn_bare_hostname, | 
					
						
							|  |  |  |         $patch['path']); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       if ($stderr) { | 
					
						
							|  |  |  |         print $stderr; | 
					
						
							|  |  |  |         exit(-1); | 
					
						
							|  |  |  |       } | 
					
						
							| 
									
										
										
										
											2011-04-30 00:18:13 -07: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-07 16:55:32 -07:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-04-30 00:18:13 -07:00
										 |  |  |   if (!$patch_applied) { | 
					
						
							|  |  |  |     print "Your database is already up-to-date.\n"; | 
					
						
							| 
									
										
										
										
											2011-04-07 16:55:32 -07:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-04-30 00:18:13 -07: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-07 16:55:32 -07:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-04-30 00:18:13 -07:00
										 |  |  | function usage() { | 
					
						
							|  |  |  |   echo | 
					
						
							| 
									
										
										
										
											2011-05-31 19:08:58 -07:00
										 |  |  |     "usage: upgrade_schema.php [-v version] [-u user -p pass] [-f] [-h]". | 
					
						
							| 
									
										
										
										
											2011-04-30 00:18:13 -07:00
										 |  |  |     "\n\n". | 
					
						
							|  |  |  |     "Run 'upgrade_schema.php -u root -p hunter2' to override the configured ". | 
					
						
							| 
									
										
										
										
											2011-05-31 19:08:58 -07: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 11:09:31 -08:00
										 |  |  |     "Run 'upgrade_schema.php -m 110' to apply all patches up to and ". | 
					
						
							|  |  |  |     "including version 110 (but nothing past).\n". | 
					
						
							| 
									
										
										
										
											2011-05-31 19:08:58 -07:00
										 |  |  |     "Use the -f flag to upgrade noninteractively, without prompting.\n". | 
					
						
							| 
									
										
										
										
											2012-03-02 11:09:31 -08:00
										 |  |  |     "Use the -d flag to do a dry run - patches that would be applied ". | 
					
						
							|  |  |  |     "will be listed, but not applied.\n". | 
					
						
							| 
									
										
										
										
											2011-05-31 19:08:58 -07:00
										 |  |  |     "Use the -h flag to show this help.\n"; | 
					
						
							| 
									
										
										
										
											2011-04-30 00:18:13 -07:00
										 |  |  |   exit(1); | 
					
						
							| 
									
										
										
										
											2011-04-07 16:55:32 -07:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2011-04-30 00:18:13 -07:00
										 |  |  | 
 |