dumpschema.php 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255
  1. #!/usr/bin/env php
  2. <?php
  3. /*
  4. * StatusNet - a distributed open-source microblogging tool
  5. * Copyright (C) 2008, 2009, StatusNet, Inc.
  6. *
  7. * This program is free software: you can redistribute it and/or modify
  8. * it under the terms of the GNU Affero General Public License as published by
  9. * the Free Software Foundation, either version 3 of the License, or
  10. * (at your option) any later version.
  11. *
  12. * This program is distributed in the hope that it will be useful,
  13. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  15. * GNU Affero General Public License for more details.
  16. *
  17. * You should have received a copy of the GNU Affero General Public License
  18. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  19. */
  20. define('INSTALLDIR', dirname(__DIR__));
  21. define('PUBLICDIR', INSTALLDIR);
  22. $helptext = <<<END_OF_CHECKSCHEMA_HELP
  23. Attempt to pull a schema definition for a given table.
  24. --all run over all defined core tables
  25. --diff show differences between the expected and live table defs
  26. --raw skip compatibility filtering for diffs
  27. --create dump SQL that would be run to update or create this table
  28. --build dump SQL that would be run to create this table fresh
  29. --checksum just output checksums from the source schema defs
  30. END_OF_CHECKSCHEMA_HELP;
  31. $longoptions = array('diff', 'all', 'create', 'update', 'raw', 'checksum');
  32. require_once INSTALLDIR.'/scripts/commandline.inc';
  33. function indentOptions($indent)
  34. {
  35. $cutoff = 3;
  36. if ($indent < $cutoff) {
  37. $space = $indent ? str_repeat(' ', $indent * 4) : '';
  38. $sep = ",";
  39. $lf = "\n";
  40. $endspace = "$lf" . ($indent ? str_repeat(' ', ($indent - 1) * 4) : '');
  41. } else {
  42. $space = '';
  43. $sep = ", ";
  44. $lf = '';
  45. $endspace = '';
  46. }
  47. if ($indent - 1 < $cutoff) {
  48. }
  49. return array($space, $sep, $lf, $endspace);
  50. }
  51. function prettyDumpArray($arr, $key=null, $indent=0)
  52. {
  53. // hack
  54. if ($key == 'primary key') {
  55. $subIndent = $indent + 2;
  56. } else {
  57. $subIndent = $indent + 1;
  58. }
  59. list($space, $sep, $lf, $endspace) = indentOptions($indent);
  60. list($inspace, $insep, $inlf, $inendspace) = indentOptions($subIndent);
  61. print "{$space}";
  62. if (!is_numeric($key)) {
  63. print "'$key' => ";
  64. }
  65. if (is_array($arr)) {
  66. print "array({$inlf}";
  67. $n = 0;
  68. foreach ($arr as $key => $row) {
  69. $n++;
  70. prettyDumpArray($row, $key, $subIndent);
  71. if ($n < count($arr)) {
  72. print "$insep$inlf";
  73. }
  74. }
  75. // hack!
  76. print "{$inendspace})";
  77. } else {
  78. print var_export($arr, true);
  79. }
  80. }
  81. function getCoreSchema($tableName)
  82. {
  83. $schema = array();
  84. include INSTALLDIR . '/db/core.php';
  85. return $schema[$tableName];
  86. }
  87. function getCoreTables()
  88. {
  89. $schema = array();
  90. include INSTALLDIR . '/db/core.php';
  91. return array_keys($schema);
  92. }
  93. function dumpTable($tableName, $live)
  94. {
  95. if ($live) {
  96. $schema = Schema::get();
  97. $def = $schema->getTableDef($tableName);
  98. } else {
  99. // hack
  100. $def = getCoreSchema($tableName);
  101. }
  102. prettyDumpArray($def, $tableName);
  103. print "\n";
  104. }
  105. function dumpBuildTable($tableName)
  106. {
  107. echo "-- \n";
  108. echo "-- $tableName\n";
  109. echo "-- \n";
  110. $schema = Schema::get();
  111. $def = getCoreSchema($tableName);
  112. $sql = $schema->buildCreateTable($tableName, $def);
  113. $sql[] = '';
  114. echo implode(";\n", $sql);
  115. echo "\n";
  116. }
  117. function dumpEnsureTable($tableName)
  118. {
  119. $schema = Schema::get();
  120. $def = getCoreSchema($tableName);
  121. $sql = $schema->buildEnsureTable($tableName, $def);
  122. if ($sql) {
  123. echo "-- \n";
  124. echo "-- $tableName\n";
  125. echo "-- \n";
  126. $sql[] = '';
  127. echo implode(";\n", $sql);
  128. echo "\n";
  129. }
  130. }
  131. function dumpDiff($tableName, $filter)
  132. {
  133. $schema = Schema::get();
  134. $def = getCoreSchema($tableName);
  135. try {
  136. $old = $schema->getTableDef($tableName);
  137. } catch (Exception $e) {
  138. // @fixme this is a terrible check :D
  139. if (preg_match('/no such table/i', $e->getMessage())) {
  140. return dumpTable($tableName, false);
  141. } else {
  142. throw $e;
  143. }
  144. }
  145. if ($filter) {
  146. //$old = $schema->filterDef($old);
  147. $def = $schema->filterDef($def);
  148. }
  149. // @hack
  150. $old = tweakPrimaryKey($old);
  151. $def = tweakPrimaryKey($def);
  152. $sections = array_unique(array_merge(array_keys($old), array_keys($def)));
  153. $final = array();
  154. foreach ($sections as $section) {
  155. if ($section == 'fields') {
  156. // this shouldn't be needed maybe... wait what?
  157. }
  158. $diff = $schema->diffArrays($old, $def, $section);
  159. $chunks = array('del', 'mod', 'add');
  160. foreach ($chunks as $chunk) {
  161. if ($diff[$chunk]) {
  162. foreach ($diff[$chunk] as $key) {
  163. if ($chunk == 'del') {
  164. $final[$section]["DEL $key"] = $old[$section][$key];
  165. } else if ($chunk == 'add') {
  166. $final[$section]["ADD $key"] = $def[$section][$key];
  167. } else if ($chunk == 'mod') {
  168. $final[$section]["OLD $key"] = $old[$section][$key];
  169. $final[$section]["NEW $key"] = $def[$section][$key];
  170. }
  171. }
  172. }
  173. }
  174. }
  175. prettyDumpArray($final, $tableName);
  176. print "\n";
  177. }
  178. function tweakPrimaryKey($def)
  179. {
  180. if (isset($def['primary key'])) {
  181. $def['primary keys'] = array('primary key' => $def['primary key']);
  182. unset($def['primary key']);
  183. }
  184. if (isset($def['description'])) {
  185. $def['descriptions'] = array('description' => $def['description']);
  186. unset($def['description']);
  187. }
  188. return $def;
  189. }
  190. function dumpChecksum($tableName)
  191. {
  192. $schema = Schema::get();
  193. $def = getCoreSchema($tableName);
  194. $updater = new SchemaUpdater($schema);
  195. $checksum = $updater->checksum($def);
  196. $old = @$updater->checksums[$tableName];
  197. if ($old == $checksum) {
  198. echo "OK $checksum $tableName\n";
  199. } else if (!$old) {
  200. echo "NEW $checksum $tableName\n";
  201. } else {
  202. echo "MOD $checksum $tableName (was $old)\n";
  203. }
  204. }
  205. if (have_option('all')) {
  206. $args = getCoreTables();
  207. }
  208. if (count($args)) {
  209. foreach ($args as $tableName) {
  210. if (have_option('diff')) {
  211. dumpDiff($tableName, !have_option('raw'));
  212. } else if (have_option('create')) {
  213. dumpBuildTable($tableName);
  214. } else if (have_option('update')) {
  215. dumpEnsureTable($tableName);
  216. } else if (have_option('checksum')) {
  217. dumpChecksum($tableName);
  218. } else {
  219. dumpTable($tableName, true);
  220. }
  221. }
  222. } else {
  223. show_help($helptext);
  224. }