@recaptime-dev's working patches + fork for Phorge, a community fork of Phabricator. (Upstream dev and stable branches are at upstream/main and upstream/stable respectively.) hq.recaptime.dev/wiki/Phorge
phorge phabricator
at recaptime-dev/main 240 lines 7.1 kB view raw
1#!/usr/bin/env php 2<?php 3 4$root = dirname(dirname(dirname(__FILE__))); 5require_once $root.'/scripts/init/init-setup.php'; 6 7$args = new PhutilArgumentParser($argv); 8$args->setTagline(pht('manage storage and schemata')); 9$args->setSynopsis(pht(<<<EOHELP 10**storage** __workflow__ [__options__] 11Manage database storage and schema versioning. 12 13**storage** upgrade 14Initialize or upgrade storage. 15 16**storage** upgrade --user __root__ --password __hunter2__ 17Use administrative credentials for schema changes. 18EOHELP 19)); 20$args->parseStandardArguments(); 21 22$default_namespace = PhabricatorLiskDAO::getDefaultStorageNamespace(); 23 24try { 25 $args->parsePartial( 26 array( 27 array( 28 'name' => 'force', 29 'short' => 'f', 30 'help' => pht( 31 'Do not prompt before performing dangerous operations.'), 32 ), 33 array( 34 'name' => 'host', 35 'param' => 'hostname', 36 'help' => pht( 37 'Operate on the database server identified by __hostname__.'), 38 ), 39 array( 40 'name' => 'ref', 41 'param' => 'ref', 42 'help' => pht( 43 'Operate on the database identified by __ref__.'), 44 ), 45 array( 46 'name' => 'user', 47 'short' => 'u', 48 'param' => 'username', 49 'help' => pht( 50 'Connect with __username__ instead of the configured default.'), 51 ), 52 array( 53 'name' => 'password', 54 'short' => 'p', 55 'param' => 'password', 56 'help' => pht('Use __password__ instead of the configured default.'), 57 ), 58 array( 59 'name' => 'namespace', 60 'param' => 'name', 61 'default' => $default_namespace, 62 'help' => pht( 63 "Use namespace __namespace__ instead of the configured ". 64 "default ('%s'). This is an advanced feature used by unit tests; ". 65 "you should not normally use this flag.", 66 $default_namespace), 67 ), 68 array( 69 'name' => 'dryrun', 70 'help' => pht( 71 'Do not actually change anything, just show what would be changed.'), 72 ), 73 )); 74} catch (PhutilArgumentUsageException $ex) { 75 $args->printUsageException($ex); 76 exit(77); 77} 78 79// First, test that the Phabricator configuration is set up correctly. After 80// we know this works we'll test any administrative credentials specifically. 81 82$refs = PhabricatorDatabaseRef::getActiveDatabaseRefs(); 83if (!$refs) { 84 throw new PhutilArgumentUsageException( 85 pht('No databases are configured.')); 86} 87 88$host = $args->getArg('host'); 89$ref_key = $args->getArg('ref'); 90if (($host !== null) || ($ref_key !== null)) { 91 if ($host && $ref_key) { 92 throw new PhutilArgumentUsageException( 93 pht( 94 'Use "--host" or "--ref" to select a database, but not both.')); 95 } 96 97 $refs = PhabricatorDatabaseRef::getActiveDatabaseRefs(); 98 99 $possible_refs = array(); 100 foreach ($refs as $possible_ref) { 101 if ($host && ($possible_ref->getHost() == $host)) { 102 $possible_refs[] = $possible_ref; 103 break; 104 } 105 if ($ref_key && ($possible_ref->getRefKey() == $ref_key)) { 106 $possible_refs[] = $possible_ref; 107 break; 108 } 109 } 110 111 if (!$possible_refs) { 112 if ($host) { 113 throw new PhutilArgumentUsageException( 114 pht( 115 'There is no configured database on host "%s". This command can '. 116 'only interact with configured databases.', 117 $host)); 118 } else { 119 throw new PhutilArgumentUsageException( 120 pht( 121 'There is no configured database with ref "%s". This command can '. 122 'only interact with configured databases.', 123 $ref_key)); 124 } 125 } 126 127 if (count($possible_refs) > 1) { 128 throw new PhutilArgumentUsageException( 129 pht( 130 'Host "%s" identifies more than one database. Use "--ref" to select '. 131 'a specific database.', 132 $host)); 133 } 134 135 $refs = $possible_refs; 136} 137 138$apis = array(); 139foreach ($refs as $ref) { 140 $default_user = $ref->getUser(); 141 $default_host = $ref->getHost(); 142 $default_port = $ref->getPort(); 143 144 $test_api = id(new PhabricatorStorageManagementAPI()) 145 ->setUser($default_user) 146 ->setHost($default_host) 147 ->setPort($default_port) 148 ->setPassword($ref->getPass()) 149 ->setNamespace($args->getArg('namespace')); 150 151 try { 152 queryfx( 153 $test_api->getConn(null), 154 'SELECT 1'); 155 } catch (AphrontQueryException $ex) { 156 $message = phutil_console_format( 157 "**%s**\n\n%s\n\n%s\n\n%s\n\n**%s**: %s\n", 158 pht('MySQL Credentials Not Configured'), 159 pht( 160 'Unable to connect to MySQL using the configured credentials. '. 161 'You must configure standard credentials before you can upgrade '. 162 'storage. Run these commands to set up credentials:'), 163 " $ ./bin/config set mysql.host __host__\n". 164 " $ ./bin/config set mysql.user __username__\n". 165 " $ ./bin/config set mysql.pass __password__", 166 pht( 167 'These standard credentials are separate from any administrative '. 168 'credentials provided to this command with __%s__ or '. 169 '__%s__, and must be configured correctly before you can proceed.', 170 '--user', 171 '--password'), 172 pht('Raw MySQL Error'), 173 $ex->getMessage()); 174 echo phutil_console_wrap($message); 175 exit(1); 176 } 177 178 if ($args->getArg('password') === null) { 179 // This is already a PhutilOpaqueEnvelope. 180 $password = $ref->getPass(); 181 } else { 182 // Put this in a PhutilOpaqueEnvelope. 183 $password = new PhutilOpaqueEnvelope($args->getArg('password')); 184 PhabricatorEnv::overrideConfig('mysql.pass', $args->getArg('password')); 185 } 186 187 $selected_user = $args->getArg('user'); 188 if ($selected_user === null) { 189 $selected_user = $default_user; 190 } 191 192 $api = id(new PhabricatorStorageManagementAPI()) 193 ->setUser($selected_user) 194 ->setHost($default_host) 195 ->setPort($default_port) 196 ->setPassword($password) 197 ->setNamespace($args->getArg('namespace')); 198 PhabricatorEnv::overrideConfig('mysql.user', $api->getUser()); 199 200 $ref->setUser($selected_user); 201 $ref->setPass($password); 202 203 try { 204 queryfx( 205 $api->getConn(null), 206 'SELECT 1'); 207 } catch (AphrontQueryException $ex) { 208 $message = phutil_console_format( 209 "**%s**\n\n%s\n\n**%s**: %s\n", 210 pht('Bad Administrative Credentials'), 211 pht( 212 'Unable to connect to MySQL using the administrative credentials '. 213 'provided with the __%s__ and __%s__ flags. Check that '. 214 'you have entered them correctly.', 215 '--user', 216 '--password'), 217 pht('Raw MySQL Error'), 218 $ex->getMessage()); 219 echo phutil_console_wrap($message); 220 exit(1); 221 } 222 223 $api->setRef($ref); 224 $apis[] = $api; 225} 226 227$workflows = id(new PhutilClassMapQuery()) 228 ->setAncestorClass(PhabricatorStorageManagementWorkflow::class) 229 ->execute(); 230 231$patches = PhabricatorSQLPatchList::buildAllPatches(); 232 233foreach ($workflows as $workflow) { 234 $workflow->setAPIs($apis); 235 $workflow->setPatches($patches); 236} 237 238$workflows[] = new PhutilHelpArgumentWorkflow(); 239 240$args->parseWorkflows($workflows);