/bin/php/ezsqldiff.php

https://github.com/GunioRobot/ezpublish · PHP · 225 lines · 212 code · 4 blank · 9 comment · 7 complexity · 42560a11c49b0e29ff5b34980a6ac389 MD5 · raw file

  1. #!/usr/bin/env php
  2. <?php
  3. /**
  4. * File containing the ezsqldiff.php script.
  5. *
  6. * @copyright Copyright (C) 1999-2011 eZ Systems AS. All rights reserved.
  7. * @license http://www.gnu.org/licenses/gpl-2.0.txt GNU General Public License v2
  8. * @version //autogentag//
  9. * @package kernel
  10. */
  11. require 'autoload.php';
  12. $cli = eZCLI::instance();
  13. $script = eZScript::instance( array( 'description' => ( "eZ Publish SQL diff\n\n" .
  14. "Displays differences between two database schemas,\n" .
  15. "and sets exit code based whether there is a difference or not\n" .
  16. "\n" .
  17. "ezsqldiff.php --type mysql --user=root stable32 stable33" ),
  18. 'use-session' => false,
  19. 'use-modules' => true,
  20. 'use-extensions' => true ) );
  21. $script->startup();
  22. $options = $script->getOptions( "[source-type:][source-host:][source-user:][source-password;][source-socket:]" .
  23. "[match-type:][match-host:][match-user:][match-password;][match-socket:]" .
  24. "[t:|type:][host:][u:|user:][p:|password;][socket:]" .
  25. "[lint-check]" .
  26. "[reverse][check-only]",
  27. "[source][match]",
  28. array( 'source-type' => ( "Which database type to use for source, can be one of:\n" .
  29. "mysql, postgresql" ),
  30. 'source-host' => "Connect to host source database",
  31. 'source-user' => "User for login to source database",
  32. 'source-password' => "Password to use when connecting to source database",
  33. 'source-socket' => 'Socket to connect to source database (only for MySQL)',
  34. 'match-type' => ( "Which database type to use for match, can be one of:\n" .
  35. "mysql, postgresql" ),
  36. 'match-host' => "Connect to host match database",
  37. 'match-user' => "User for login to match database",
  38. 'match-password' => "Password to use when connecting to match database",
  39. 'match-socket' => 'Socket to connect to match database (only for MySQL)',
  40. 'type' => ( "Which database type to use for match and source, can be one of:\n" .
  41. "mysql, postgresql" ),
  42. 'host' => "Connect to host match and source database",
  43. 'user' => "User for login to match and source database",
  44. 'password' => "Password to use when connecting to match and source database",
  45. 'socket' => 'Socket to connect to match and source database (only for MySQL)',
  46. 'lint-check' => 'Instead of comparing 2 datase schemas, verify source database schema for standards compliance',
  47. 'reverse' => "Reverse the differences",
  48. 'check-only' => "Don't show SQLs for the differences, just set exit code and return"
  49. ) );
  50. $script->initialize();
  51. if ( count( $options['arguments'] ) < 1 )
  52. {
  53. $cli->error( "Missing source database" );
  54. $script->shutdown( 1 );
  55. }
  56. if ( count( $options['arguments'] ) < 2 and
  57. !$options['lint-check'] )
  58. {
  59. $cli->error( "Missing match database" );
  60. $script->shutdown( 1 );
  61. }
  62. $sourceType = $options['source-type'] ? $options['source-type'] : $options['type'];
  63. $sourceDBHost = $options['source-host'] ? $options['source-host'] : $options['host'];
  64. $sourceDBUser = $options['source-user'] ? $options['source-user'] : $options['user'];
  65. $sourceDBPassword = $options['source-password'] ? $options['source-password'] : $options['password'];
  66. $sourceDBSocket = $options['source-socket'] ? $options['source-socket'] : $options['socket'];
  67. $sourceDB = $options['arguments'][0];
  68. if( !is_string( $sourceDBPassword ) )
  69. $sourceDBPassword = '';
  70. $matchType = $options['match-type'] ? $options['match-type'] : $options['type'];
  71. $matchDBHost = $options['match-host'] ? $options['match-host'] : $options['host'];
  72. $matchDBUser = $options['match-user'] ? $options['match-user'] : $options['user'];
  73. $matchDBPassword = $options['match-password'] ? $options['match-password'] : $options['password'];
  74. $matchDBSocket = $options['match-socket'] ? $options['match-socket'] : $options['socket'];
  75. $matchDB = count( $options['arguments'] ) >= 2 ? $options['arguments'][1] : '';
  76. if ( !is_string( $matchDBPassword ) )
  77. $matchDBPassword = '';
  78. if ( strlen( trim( $sourceType ) ) == 0 )
  79. {
  80. $cli->error( "No source type chosen" );
  81. $script->shutdown( 1 );
  82. }
  83. if ( strlen( trim( $matchType ) ) == 0 )
  84. {
  85. if ( !$options['lint-check'] )
  86. {
  87. $cli->error( "No match type chosen" );
  88. $script->shutdown( 1 );
  89. }
  90. }
  91. $ini = eZINI::instance();
  92. function loadDatabaseSchema( $type, $host, $user, $password, $socket, $db, $cli )
  93. {
  94. $dbSchema = false;
  95. if ( file_exists( $db ) and is_file( $db ) )
  96. {
  97. $dbSchema = eZDbSchema::instance( array( 'type' => $type,
  98. 'schema' => eZDbSchema::read( $db ) ) );
  99. return $dbSchema;
  100. }
  101. else
  102. {
  103. $parameters = array( 'use_defaults' => false,
  104. 'server' => $host,
  105. 'user' => $user,
  106. 'password' => $password,
  107. 'database' => $db );
  108. if ( $socket )
  109. $parameters['socket'] = $socket;
  110. $dbInstance = eZDB::instance( 'ez' . $type,
  111. $parameters,
  112. true );
  113. if ( !is_object( $dbInstance ) )
  114. {
  115. $cli->error( 'Could not initialize database:' );
  116. $cli->error( '* No database handler was found for $type' );
  117. return $dbSchema;
  118. }
  119. if ( !$dbInstance->isConnected() )
  120. {
  121. $cli->error( "Could not initialize database:" );
  122. $msg = "* Tried database '$db'";
  123. if ( strlen( $host ) > 0 )
  124. {
  125. $msg .= " at host '$host'";
  126. }
  127. else
  128. {
  129. $msg .= " locally";
  130. }
  131. if ( strlen( $user ) > 0 )
  132. {
  133. $msg .= " with user '$user'";
  134. }
  135. if ( strlen( $password ) > 0 )
  136. $msg .= " and with a password";
  137. $cli->error( $msg );
  138. // Fetch the database error message if there is one
  139. // It will give more feedback to the user what is wrong
  140. $msg = $dbInstance->errorMessage();
  141. if ( $msg )
  142. {
  143. $number = $dbInstance->errorNumber();
  144. if ( $number > 0 )
  145. $msg .= '(' . $number . ')';
  146. $cli->error( '* ' . $msg );
  147. }
  148. return $dbSchema;
  149. }
  150. return eZDbSchema::instance( $dbInstance );
  151. }
  152. }
  153. function loadLintSchema( $dbSchema, $cli )
  154. {
  155. return new eZLintSchema( false, $dbSchema );
  156. }
  157. $sourceSchema = loadDatabaseSchema( $sourceType, $sourceDBHost, $sourceDBUser, $sourceDBPassword, $sourceDBSocket, $sourceDB, $cli );
  158. if ( !$sourceSchema )
  159. {
  160. $cli->error( "Failed to load schema from source database" );
  161. $script->shutdown( 1 );
  162. }
  163. if ( $options['lint-check'] )
  164. {
  165. $matchType = $sourceType;
  166. $matchSchema = $sourceSchema;
  167. unset( $sourceSchema );
  168. $sourceSchema = loadLintSchema( $matchSchema, $cli );
  169. }
  170. else
  171. {
  172. $matchSchema = loadDatabaseSchema( $matchType, $matchDBHost, $matchDBUser, $matchDBPassword, $matchDBSocket, $matchDB, $cli );
  173. if ( !$matchSchema )
  174. {
  175. $cli->error( "Failed to load schema from match database" );
  176. $script->shutdown( 1 );
  177. }
  178. }
  179. if ( $options['reverse'] )
  180. {
  181. $differences = eZDbSchemaChecker::diff( $sourceSchema->schema(), $matchSchema->schema(), $sourceType, $matchType );
  182. if ( !$options['check-only'] )
  183. {
  184. $cli->output( "-- Difference in SQL commands for " . $sourceSchema->schemaName() );
  185. $sql = $sourceSchema->generateUpgradeFile( $differences );
  186. $cli->output( $sql );
  187. }
  188. }
  189. else
  190. {
  191. $differences = eZDbSchemaChecker::diff( $matchSchema->schema(), $sourceSchema->schema(), $matchType, $sourceType );
  192. if ( !$options['check-only'] )
  193. {
  194. $cli->output( "-- Difference in SQL commands from " . $sourceSchema->schemaName() . " to " . $matchSchema->schemaName() );
  195. $sql = $matchSchema->generateUpgradeFile( $differences );
  196. $cli->output( $sql );
  197. }
  198. }
  199. if ( count( $differences ) > 0 )
  200. $script->setExitCode( 1 );
  201. $script->shutdown();
  202. ?>