#!/usr/bin/env php <?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. */ $root = dirname(dirname(dirname(__FILE__))); require_once $root.'/scripts/__init_script__.php'; require_once $root.'/scripts/__init_env__.php'; phutil_require_module('phutil', 'console'); const TABLE_NAME = 'schema_version'; if (isset($argv[1]) && !is_numeric($argv[1])) { print "USAGE: ./update_schema.php [first_patch_version]\n\n". "run './update_schema.php 12' to apply all patches starting from ". "version 12.\n". "run './update_schema.php' to apply all patches that are new since\n". "the last time this script was run\n\n"; exit(0); } echo phutil_console_wrap( "Before running this script, you should take down the Phabricator web ". "interface and stop any running Phabricator daemons."); if (!phutil_console_confirm('Are you ready to continue?')) { echo "Cancelled.\n"; exit(1); } // Use always the version from the commandline if it is defined $next_version = isset($argv[1]) ? (int)$argv[1] : null; // Dummy class needed for creating our database class DummyUser extends PhabricatorLiskDAO { public function getApplicationName() { return 'user'; } } // Class needed for setting up the actual SQL connection class PhabricatorSchemaVersion extends PhabricatorLiskDAO { public function getApplicationName() { return 'meta_data'; } } // Connect to 'phabricator_user' db first to create our db $conn = id(new DummyUser())->establishConnection('w'); $create_sql = <<<END CREATE DATABASE IF NOT EXISTS `phabricator_meta_data`; END; queryfx($conn, $create_sql); // 'phabricator_meta_data' database exists, let's connect to it now $conn = id(new PhabricatorSchemaVersion())->establishConnection('w'); $create_sql = <<<END CREATE TABLE IF NOT EXISTS phabricator_meta_data.`schema_version` ( `version` INTEGER not null ); END; queryfx($conn, $create_sql); // Get the version only if commandline argument wasn't given if ($next_version === null) { $version = queryfx_one( $conn, 'SELECT * FROM %T', 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; } // 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'); $patch_applied = false; foreach ($patches as $patch) { if ($patch['version'] < $next_version) { continue; } print "Applying patch {$patch['file']}\n"; $path = Filesystem::resolvePath($patches_dir.$patch['file']); $user = PhabricatorEnv::getEnvConfig('mysql.user'); $pass = PhabricatorEnv::getEnvConfig('mysql.pass'); $host = PhabricatorEnv::getEnvConfig('mysql.host'); list($stdout, $stderr) = execx( "mysql --user=%s --password=%s --host=%s < %s", $user, $pass, $host, $path); if ($stderr) { print $stderr; exit(-1); } // 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 %T', TABLE_NAME); queryfx($conn, 'INSERT INTO %T values (%d)', TABLE_NAME, $patch['version']); $patch_applied = true; } if (!$patch_applied) { print "Your database is already up-to-date\n"; }