percona_migrator 0.1.0.rc.4 → 0.1.0.rc.5
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +12 -2
- data/Gemfile +2 -0
- data/README.md +1 -1
- data/Rakefile +2 -2
- data/lib/active_record/connection_adapters/percona_adapter.rb +8 -5
- data/lib/percona_migrator/cli_generator.rb +3 -3
- data/lib/percona_migrator/runner.rb +56 -35
- data/lib/percona_migrator/version.rb +1 -1
- data/test_database.rb +32 -6
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: e7301e478b66a555e4abe723cd9429914fba7820
|
4
|
+
data.tar.gz: fbf40c010ac9272f913b1e79285cb5f61fb11839
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 39543206254ddc6f383446adca091ead90f3ac4a879dad0f7b246b8443d3bbeadc5eb95500fa26040fb8c28ef6182ad94e0620a1a4e8dd593f885f057555ed41
|
7
|
+
data.tar.gz: 011386f3f3e8866fb9db4c19c98f9e050c4899168bb5c0eb9d78ddd56451ad5eeb89caaa3973f7574f21038b89dbcda4f511353103c760f577007043e8f82af0
|
data/CHANGELOG.md
CHANGED
@@ -6,13 +6,23 @@ Please follow the format in [Keep a Changelog](http://keepachangelog.com/)
|
|
6
6
|
|
7
7
|
## [Unreleased]
|
8
8
|
|
9
|
+
## [0.1.0.rc.5] - 2016-03-29
|
10
|
+
|
11
|
+
### Changed
|
12
|
+
|
13
|
+
- Raise a ActiveRecord::StatementInvalid on failed migration. It also provides
|
14
|
+
more detailed error message when possible such as pt-onlin-schema-change
|
15
|
+
being missing.
|
16
|
+
|
9
17
|
## [0.1.0.rc.4] - 2016-03-15
|
10
18
|
|
11
19
|
### Added
|
12
20
|
|
13
21
|
- Support #drop_table
|
14
|
-
- Support
|
15
|
-
|
22
|
+
- Support for foreing keys in db/schema.rb when using [Foreigner
|
23
|
+
gem](https://github.com/matthuhiggins/foreigner) in Rails 3 apps. This allows to
|
24
|
+
define foreign keys with #execute, but does not provide support for
|
25
|
+
#add_foreign_key yet.
|
16
26
|
|
17
27
|
## [0.1.0.rc.3] - 2016-03-10
|
18
28
|
|
data/Gemfile
CHANGED
data/README.md
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
# PerconaMigrator [![Build Status](https://travis-ci.org/redbooth/percona_migrator.svg?branch=master)](https://travis-ci.org/redbooth/percona_migrator)
|
1
|
+
# PerconaMigrator [![Build Status](https://travis-ci.org/redbooth/percona_migrator.svg?branch=master)](https://travis-ci.org/redbooth/percona_migrator) [![Code Climate](https://codeclimate.com/github/redbooth/percona_migrator/badges/gpa.svg)](https://codeclimate.com/github/redbooth/percona_migrator)
|
2
2
|
|
3
3
|
Percona Migrator is a tool for running online and non-blocking
|
4
4
|
DDL `ActiveRecord::Migrations` using `pt-online-schema-change` command-line tool of
|
data/Rakefile
CHANGED
@@ -6,12 +6,12 @@ require './test_database'
|
|
6
6
|
|
7
7
|
RSpec::Core::RakeTask.new(:spec)
|
8
8
|
|
9
|
-
task :
|
9
|
+
task default: :spec
|
10
10
|
|
11
11
|
namespace :db do
|
12
12
|
desc 'Create the test database'
|
13
13
|
task :create do
|
14
14
|
config = Configuration.new
|
15
|
-
TestDatabase.new(config).
|
15
|
+
TestDatabase.new(config).setup_test_database
|
16
16
|
end
|
17
17
|
end
|
@@ -83,7 +83,7 @@ module ActiveRecord
|
|
83
83
|
def add_column(table_name, column_name, type, options = {})
|
84
84
|
super
|
85
85
|
command = cli_generator.generate(table_name, @sql)
|
86
|
-
runner.execute(command)
|
86
|
+
log(@sql, nil) { runner.execute(command) }
|
87
87
|
end
|
88
88
|
|
89
89
|
# Removes the column(s) from the table definition
|
@@ -93,7 +93,7 @@ module ActiveRecord
|
|
93
93
|
def remove_column(table_name, *column_names)
|
94
94
|
super
|
95
95
|
command = cli_generator.generate(table_name, @sql)
|
96
|
-
runner.execute(command)
|
96
|
+
log(@sql, nil) { runner.execute(command) }
|
97
97
|
end
|
98
98
|
|
99
99
|
# Adds a new index to the table
|
@@ -106,7 +106,7 @@ module ActiveRecord
|
|
106
106
|
execute "ADD #{index_type} INDEX #{quote_column_name(index_name)} (#{index_columns})#{index_options}"
|
107
107
|
|
108
108
|
command = cli_generator.generate(table_name, @sql)
|
109
|
-
runner.execute(command)
|
109
|
+
log(@sql, nil) { runner.execute(command) }
|
110
110
|
end
|
111
111
|
|
112
112
|
# Remove the given index from the table.
|
@@ -118,7 +118,7 @@ module ActiveRecord
|
|
118
118
|
execute "DROP INDEX #{quote_column_name(index_name)}"
|
119
119
|
|
120
120
|
command = cli_generator.generate(table_name, @sql)
|
121
|
-
runner.execute(command)
|
121
|
+
log(@sql, nil) { runner.execute(command) }
|
122
122
|
end
|
123
123
|
|
124
124
|
# Records the SQL statement to be executed. This is used to then delegate
|
@@ -139,7 +139,7 @@ module ActiveRecord
|
|
139
139
|
def percona_execute(sql, name)
|
140
140
|
if alter_statement?(sql)
|
141
141
|
command = cli_generator.parse_statement(sql)
|
142
|
-
runner.execute(command)
|
142
|
+
log(sql, nil) { runner.execute(command) }
|
143
143
|
else
|
144
144
|
mysql_adapter.execute(sql, name)
|
145
145
|
end
|
@@ -154,6 +154,9 @@ module ActiveRecord
|
|
154
154
|
yield mysql_adapter.execute(sql, name)
|
155
155
|
end
|
156
156
|
|
157
|
+
def error_number(exception)
|
158
|
+
end
|
159
|
+
|
157
160
|
private
|
158
161
|
|
159
162
|
attr_reader :mysql_adapter, :logger, :runner, :cli_generator
|
@@ -47,7 +47,7 @@ module PerconaMigrator
|
|
47
47
|
end
|
48
48
|
|
49
49
|
# Generates the percona command. Fills all the connection credentials from
|
50
|
-
# the current AR connection, but that can amended via ENV-vars:
|
50
|
+
# the current AR connection, but that can be amended via ENV-vars:
|
51
51
|
# PERCONA_DB_HOST, PERCONA_DB_USER, PERCONA_DB_PASSWORD, PERCONA_DB_NAME
|
52
52
|
# Table name can't not be amended, it populates automatically from the
|
53
53
|
# migration data
|
@@ -59,7 +59,7 @@ module PerconaMigrator
|
|
59
59
|
alter_argument = AlterArgument.new(statement)
|
60
60
|
dsn = DSN.new(database, table_name)
|
61
61
|
|
62
|
-
"#{
|
62
|
+
"#{self} #{dsn} #{alter_argument}"
|
63
63
|
end
|
64
64
|
|
65
65
|
# Generates the percona command for a raw MySQL statement. Fills all the
|
@@ -74,7 +74,7 @@ module PerconaMigrator
|
|
74
74
|
alter_argument = AlterArgument.new(statement)
|
75
75
|
dsn = DSN.new(database, alter_argument.table_name)
|
76
76
|
|
77
|
-
"#{
|
77
|
+
"#{self} #{dsn} #{alter_argument}"
|
78
78
|
end
|
79
79
|
|
80
80
|
private
|
@@ -1,23 +1,48 @@
|
|
1
1
|
require 'open3'
|
2
2
|
|
3
3
|
module PerconaMigrator
|
4
|
+
class Error < StandardError; end
|
5
|
+
|
6
|
+
# Used when for whatever reason we couldn't get the spawned process'
|
7
|
+
# status.
|
8
|
+
class NoStatusError < Error
|
9
|
+
def message
|
10
|
+
'Status could not be retrieved'.freeze
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
# Used when the spawned process failed by receiving a signal.
|
15
|
+
# pt-online-schema-change returns "SIGSEGV (signal 11)" on failures.
|
16
|
+
class SignalError < Error
|
17
|
+
attr_reader :status
|
18
|
+
|
19
|
+
# Constructor
|
20
|
+
#
|
21
|
+
# @param status [Process::Status]
|
22
|
+
def initialize(status)
|
23
|
+
super
|
24
|
+
@status = status
|
25
|
+
end
|
26
|
+
|
27
|
+
def message
|
28
|
+
status.to_s
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
class CommandNotFoundError < Error
|
33
|
+
def message
|
34
|
+
'Please install pt-online-schema-change. Check: https://www.percona.com/doc/percona-toolkit for further details'
|
35
|
+
end
|
36
|
+
end
|
4
37
|
|
5
38
|
# It executes pt-online-schema-change commands in a new process and gets its
|
6
39
|
# output and status
|
7
40
|
class Runner
|
41
|
+
COMMAND_NOT_FOUND = 127
|
8
42
|
|
9
43
|
NONE = "\e[0m"
|
10
44
|
CYAN = "\e[38;5;86m"
|
11
45
|
GREEN = "\e[32m"
|
12
|
-
RED = "\e[31m"
|
13
|
-
|
14
|
-
# Executes the given command printing the output to the logger
|
15
|
-
#
|
16
|
-
# @param command [String]
|
17
|
-
# @param logger [IO]
|
18
|
-
def self.execute(command, logger)
|
19
|
-
new(command, logger).execute
|
20
|
-
end
|
21
46
|
|
22
47
|
# Constructor
|
23
48
|
#
|
@@ -33,11 +58,7 @@ module PerconaMigrator
|
|
33
58
|
# @return [Boolean]
|
34
59
|
def execute(command)
|
35
60
|
@command = command
|
36
|
-
|
37
|
-
log_started
|
38
|
-
run_command
|
39
|
-
log_finished
|
40
|
-
|
61
|
+
logging { run_command }
|
41
62
|
status
|
42
63
|
end
|
43
64
|
|
@@ -45,6 +66,15 @@ module PerconaMigrator
|
|
45
66
|
|
46
67
|
attr_reader :command, :logger, :status
|
47
68
|
|
69
|
+
# Logs the start and end of the execution
|
70
|
+
#
|
71
|
+
# @yield
|
72
|
+
def logging
|
73
|
+
log_started
|
74
|
+
yield
|
75
|
+
log_finished
|
76
|
+
end
|
77
|
+
|
48
78
|
# TODO: log as a migration logger subitem
|
49
79
|
#
|
50
80
|
# Logs when the execution started
|
@@ -56,33 +86,24 @@ module PerconaMigrator
|
|
56
86
|
#
|
57
87
|
# @raise [Errno::ENOENT] if pt-online-schema-change can't be found
|
58
88
|
def run_command
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
if status.nil?
|
65
|
-
Kernel.warn("Error running '#{command}': status could not be retrieved")
|
89
|
+
message = nil
|
90
|
+
Open3.popen3(command) do |_stdin, stdout, stderr, waith_thr|
|
91
|
+
@status = waith_thr.value
|
92
|
+
message = stderr.read
|
93
|
+
logger.info(stdout.read)
|
66
94
|
end
|
67
95
|
|
68
|
-
|
69
|
-
|
70
|
-
|
96
|
+
raise NoStatusError if status.nil?
|
97
|
+
raise SignalError.new(status) if status.signaled?
|
98
|
+
raise CommandNotFoundError if status.exitstatus == COMMAND_NOT_FOUND
|
71
99
|
|
72
|
-
|
73
|
-
raise Errno::ENOENT, "Please install pt-online-schema-change. Check: https://www.percona.com/doc/percona-toolkit"
|
100
|
+
raise Error, message unless status.success?
|
74
101
|
end
|
75
102
|
|
76
|
-
# Logs the status of the execution once it's finished
|
103
|
+
# Logs the status of the execution once it's finished. At this point we
|
104
|
+
# know it's a success
|
77
105
|
def log_finished
|
78
|
-
|
79
|
-
|
80
|
-
value = status.exitstatus
|
81
|
-
return unless value
|
82
|
-
|
83
|
-
message = value.zero? ? "#{GREEN}Done!#{NONE}" : "#{RED}Failed!#{NONE}"
|
84
|
-
|
85
|
-
logger.info("\n#{message}")
|
106
|
+
logger.info("\n#{GREEN}Done!#{NONE}")
|
86
107
|
end
|
87
108
|
end
|
88
109
|
end
|
data/test_database.rb
CHANGED
@@ -1,17 +1,33 @@
|
|
1
|
+
# Setups the test database with the schema_migrations table that ActiveRecord
|
2
|
+
# requires for the migrations, plus a table for the Comment model used throught
|
3
|
+
# the tests.
|
4
|
+
#
|
1
5
|
class TestDatabase
|
6
|
+
|
7
|
+
# Constructor
|
8
|
+
#
|
9
|
+
# @param config [Hash]
|
2
10
|
def initialize(config)
|
3
11
|
@config = config
|
4
12
|
end
|
5
13
|
|
6
|
-
# Creates the
|
7
|
-
|
8
|
-
|
9
|
-
|
14
|
+
# Creates the test database, the schema_migrations and the comments tables.
|
15
|
+
# It drops any of them if they already exist
|
16
|
+
def setup
|
17
|
+
setup_test_database
|
18
|
+
drop_and_create_schema_migrations_table
|
19
|
+
end
|
20
|
+
|
21
|
+
# Creates the percona_migrator_test database and the comments table in it.
|
22
|
+
# Before, it drops both if they already exist
|
23
|
+
def setup_test_database
|
24
|
+
drop_and_create_test_database
|
25
|
+
drop_and_create_comments_table
|
10
26
|
end
|
11
27
|
|
12
28
|
# Creates the ActiveRecord's schema_migrations table required for
|
13
|
-
# migrations to work
|
14
|
-
def
|
29
|
+
# migrations to work. Before, it drops the table if it already exists
|
30
|
+
def drop_and_create_schema_migrations_table
|
15
31
|
%x(#{mysql_command} "USE percona_migrator_test; DROP TABLE IF EXISTS schema_migrations; CREATE TABLE schema_migrations ( version varchar(255) COLLATE utf8_unicode_ci NOT NULL, UNIQUE KEY unique_schema_migrations (version)) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci")
|
16
32
|
end
|
17
33
|
|
@@ -19,6 +35,16 @@ class TestDatabase
|
|
19
35
|
|
20
36
|
attr_reader :config
|
21
37
|
|
38
|
+
def drop_and_create_test_database
|
39
|
+
%x(#{mysql_command} "DROP DATABASE IF EXISTS percona_migrator_test; CREATE DATABASE percona_migrator_test DEFAULT CHARACTER SET utf8 DEFAULT COLLATE utf8_unicode_ci;")
|
40
|
+
end
|
41
|
+
|
42
|
+
def drop_and_create_comments_table
|
43
|
+
%x(#{mysql_command} "USE percona_migrator_test; DROP TABLE IF EXISTS comments; CREATE TABLE comments ( id int(12) NOT NULL AUTO_INCREMENT, PRIMARY KEY (id)) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;")
|
44
|
+
end
|
45
|
+
|
46
|
+
# Returns the command to run the mysql client. It uses the crendentials from
|
47
|
+
# the provided config
|
22
48
|
def mysql_command
|
23
49
|
"mysql --user=#{config['username']} --password=#{config['password']} -e"
|
24
50
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: percona_migrator
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.0.rc.
|
4
|
+
version: 0.1.0.rc.5
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Ilya Zayats
|
@@ -10,7 +10,7 @@ authors:
|
|
10
10
|
autorequire:
|
11
11
|
bindir: bin
|
12
12
|
cert_chain: []
|
13
|
-
date: 2016-03-
|
13
|
+
date: 2016-03-29 00:00:00.000000000 Z
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
16
16
|
name: rails
|