rubyrep 1.1.2 → 1.2.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.gemtest +0 -0
- data/History.txt +9 -0
- data/bin/rubyrep +0 -0
- data/config/hoe.rb +15 -17
- data/lib/rubyrep.rb +1 -1
- data/lib/rubyrep/connection_extenders/connection_extenders.rb +14 -1
- data/lib/rubyrep/connection_extenders/jdbc_extender.rb +4 -19
- data/lib/rubyrep/proxy_connection.rb +5 -0
- data/lib/rubyrep/replication_difference.rb +4 -0
- data/lib/rubyrep/replication_extenders/postgresql_replication.rb +14 -1
- data/lib/rubyrep/replication_run.rb +37 -11
- data/lib/rubyrep/replication_runner.rb +7 -1
- data/lib/rubyrep/table_scan_helper.rb +9 -1
- data/lib/rubyrep/version.rb +2 -2
- data/sims/performance/performance.rake +3 -2
- data/spec/connection_extenders_registration_spec.rb +5 -1
- data/spec/proxy_connection_spec.rb +14 -2
- data/spec/replication_run_spec.rb +62 -0
- data/spec/table_scan_helper_spec.rb +7 -0
- data/tasks/database.rake +1 -1
- data/tasks/rspec.rake +3 -7
- metadata +29 -16
data/.gemtest
ADDED
File without changes
|
data/History.txt
CHANGED
@@ -1,3 +1,12 @@
|
|
1
|
+
== 1.2.0 2011-03-07
|
2
|
+
|
3
|
+
* Feature: compatibility with Rails 3
|
4
|
+
* Feature: do not replicate record updates that didn't change any fields (props to daudo)
|
5
|
+
* Bug fix: reducing deadlock problems (props to gtanzillo)
|
6
|
+
* Bug fix: adding missing schema prefix in PostgreSQL triggers
|
7
|
+
* Bug fix: scans / syncs fail due to incorrect handling of case sensitivity of string primary key columns
|
8
|
+
* Bug fix: reducing risk of foreign key conflicts during replication (props for root cause analysis to TonyB)
|
9
|
+
|
1
10
|
== 1.1.2 2009-05-10
|
2
11
|
|
3
12
|
* Bug fix: escape primary keys in replication triggers
|
data/bin/rubyrep
CHANGED
File without changes
|
data/config/hoe.rb
CHANGED
@@ -45,25 +45,23 @@ end
|
|
45
45
|
|
46
46
|
# Generate all the Rake tasks
|
47
47
|
# Run 'rake -T' to see list of generated tasks (from gem root directory)
|
48
|
-
hoe = Hoe.
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
48
|
+
hoe = Hoe.spec(GEM_NAME) do
|
49
|
+
self.version = VERS
|
50
|
+
developer AUTHOR, EMAIL
|
51
|
+
description = DESCRIPTION
|
52
|
+
summary = DESCRIPTION
|
53
|
+
url = HOMEPATH
|
54
|
+
rubyforge_name = RUBYFORGE_PROJECT if RUBYFORGE_PROJECT
|
55
|
+
test_globs = ["test/**/test_*.rb"]
|
56
|
+
clean_globs |= ['**/.*.sw?', '*.gem', '.config', '**/.DS_Store'] #An array of file patterns to delete on clean.
|
57
|
+
|
58
58
|
# == Optional
|
59
|
-
|
60
|
-
#
|
61
|
-
|
62
|
-
|
63
|
-
['activerecord' , '>= 2.3.5']
|
64
|
-
]
|
59
|
+
changes = paragraphs_of("History.txt", 0..1).join("\\n\\n")
|
60
|
+
#extra_deps = [] # An array of rubygem dependencies [name, version], e.g. [ ['active_support', '>= 1.3.1'] ]
|
61
|
+
extra_deps << ['activesupport', '>= 3.0.5']
|
62
|
+
extra_deps << ['activerecord' , '>= 3.0.5']
|
65
63
|
|
66
|
-
#
|
64
|
+
#spec_extras = {} # A hash of extra values to set in the gemspec.
|
67
65
|
|
68
66
|
end
|
69
67
|
|
data/lib/rubyrep.rb
CHANGED
@@ -1,3 +1,8 @@
|
|
1
|
+
class ActiveRecord::ConnectionAdapters::AbstractAdapter
|
2
|
+
# The current log subscriber
|
3
|
+
attr_accessor :log_subscriber
|
4
|
+
end
|
5
|
+
|
1
6
|
class ActiveRecord::ConnectionAdapters::Column
|
2
7
|
# Bug in ActiveRecord parsing of PostgreSQL timestamps with microseconds:
|
3
8
|
# Certain values are incorrectly rounded, thus ending up with timestamps
|
@@ -107,9 +112,17 @@ module RR
|
|
107
112
|
if config[:logger].respond_to?(:debug)
|
108
113
|
logger = config[:logger]
|
109
114
|
else
|
110
|
-
logger =
|
115
|
+
logger = ActiveSupport::BufferedLogger.new(config[:logger])
|
111
116
|
end
|
112
117
|
db_connection.instance_variable_set :@logger, logger
|
118
|
+
if ActiveSupport.const_defined?(:Notifications)
|
119
|
+
connection_object_id = db_connection.object_id
|
120
|
+
db_connection.log_subscriber = ActiveSupport::Notifications.subscribe("sql.active_record") do |name, start, finish, id, payload|
|
121
|
+
if payload[:connection_id] == connection_object_id and logger.debug?
|
122
|
+
logger.debug payload[:sql].squeeze(" ")
|
123
|
+
end
|
124
|
+
end
|
125
|
+
end
|
113
126
|
end
|
114
127
|
end
|
115
128
|
|
@@ -58,23 +58,8 @@ module RR
|
|
58
58
|
end
|
59
59
|
end
|
60
60
|
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
# And here comes the monkey patch to revert it again...
|
66
|
-
require 'active_record/connection_adapters/jdbc_adapter_spec'
|
67
|
-
require 'jdbc_adapter/jdbc_sqlite3'
|
68
|
-
module ::ActiveRecord
|
69
|
-
module ConnectionAdapters
|
70
|
-
class JdbcColumn < Column
|
71
|
-
def self.string_to_binary(value)
|
72
|
-
value
|
73
|
-
end
|
74
|
-
|
75
|
-
def self.binary_to_string(value)
|
76
|
-
value
|
77
|
-
end
|
78
|
-
end
|
79
|
-
end
|
61
|
+
require 'activerecord-jdbc-adapter'
|
62
|
+
if ArJdbc.const_defined?(:PostgreSQL)
|
63
|
+
ArJdbc::PostgreSQL::RecordNotUnique = ActiveRecord::RecordNotUnique unless ArJdbc::PostgreSQL.const_defined?(:RecordNotUnique)
|
64
|
+
ArJdbc::PostgreSQL::InvalidForeignKey = ActiveRecord::InvalidForeignKey unless ArJdbc::PostgreSQL.const_defined?(:InvalidForeignKey)
|
80
65
|
end
|
@@ -19,6 +19,10 @@ module RR
|
|
19
19
|
# * :+no_diff+: changes in both databases constitute no difference
|
20
20
|
attr_accessor :type
|
21
21
|
|
22
|
+
# Is set to +true+ if first replication attempt failed but it should be tried again later
|
23
|
+
attr_accessor :second_chance
|
24
|
+
alias_method :second_chance?, :second_chance
|
25
|
+
|
22
26
|
# A hash with keys :+left+ and / or :+right+.
|
23
27
|
# Hash values are LoggedChange instances.
|
24
28
|
def changes
|
@@ -45,13 +45,25 @@ module RR
|
|
45
45
|
activity_check = ""
|
46
46
|
if params[:exclude_rr_activity] then
|
47
47
|
activity_check = <<-end_sql
|
48
|
-
PERFORM ACTIVE FROM #{params[:activity_table]};
|
48
|
+
PERFORM ACTIVE FROM #{schema_prefix}#{params[:activity_table]};
|
49
49
|
IF FOUND THEN
|
50
50
|
RETURN NULL;
|
51
51
|
END IF;
|
52
52
|
end_sql
|
53
53
|
end
|
54
54
|
|
55
|
+
version_string = select_value("select version();")
|
56
|
+
version = version_string.gsub(/^\s*postgresql\s*([0-9.]+).*$/i, '\1')
|
57
|
+
if version >= '8.4'
|
58
|
+
modification_check = <<-end_sql
|
59
|
+
IF NEW IS NOT DISTINCT FROM OLD THEN
|
60
|
+
RETURN NULL;
|
61
|
+
END IF;
|
62
|
+
end_sql
|
63
|
+
else
|
64
|
+
modification_check = ""
|
65
|
+
end
|
66
|
+
|
55
67
|
# now create the trigger
|
56
68
|
execute(<<-end_sql)
|
57
69
|
CREATE OR REPLACE FUNCTION "#{params[:trigger_name]}"() RETURNS TRIGGER AS $change_trigger$
|
@@ -61,6 +73,7 @@ module RR
|
|
61
73
|
INSERT INTO #{schema_prefix}#{params[:log_table]}(change_table, change_key, change_type, change_time)
|
62
74
|
SELECT '#{params[:table]}', #{key_clause('OLD', params)}, 'D', now();
|
63
75
|
ELSIF (TG_OP = 'UPDATE') THEN
|
76
|
+
#{modification_check}
|
64
77
|
INSERT INTO #{schema_prefix}#{params[:log_table]}(change_table, change_key, change_new_key, change_type, change_time)
|
65
78
|
SELECT '#{params[:table]}', #{key_clause('OLD', params)}, #{key_clause('NEW', params)}, 'U', now();
|
66
79
|
ELSIF (TG_OP = 'INSERT') THEN
|
@@ -11,6 +11,11 @@ module RR
|
|
11
11
|
# The current TaskSweeper
|
12
12
|
attr_accessor :sweeper
|
13
13
|
|
14
|
+
# An array of ReplicationDifference which originally failed replication but should be tried one more time
|
15
|
+
def second_chancers
|
16
|
+
@second_chancers ||= []
|
17
|
+
end
|
18
|
+
|
14
19
|
# Returns the current ReplicationHelper; creates it if necessary
|
15
20
|
def helper
|
16
21
|
@helper ||= ReplicationHelper.new(self)
|
@@ -39,6 +44,20 @@ module RR
|
|
39
44
|
end
|
40
45
|
end
|
41
46
|
|
47
|
+
# Returns the next available ReplicationDifference.
|
48
|
+
# (Either new unprocessed differences or if not available, the first available 'second chancer'.)
|
49
|
+
#
|
50
|
+
def load_difference
|
51
|
+
@loaders ||= LoggedChangeLoaders.new(session)
|
52
|
+
@loaders.update # ensure the cache of change log records is up-to-date
|
53
|
+
diff = ReplicationDifference.new @loaders
|
54
|
+
diff.load
|
55
|
+
unless diff.loaded? or second_chancers.empty?
|
56
|
+
diff = second_chancers.shift
|
57
|
+
end
|
58
|
+
diff
|
59
|
+
end
|
60
|
+
|
42
61
|
# Executes the replication run.
|
43
62
|
def run
|
44
63
|
return unless [:left, :right].any? do |database|
|
@@ -57,29 +76,36 @@ module RR
|
|
57
76
|
# Check for this and if timed out, return (silently).
|
58
77
|
return if sweeper.terminated?
|
59
78
|
|
60
|
-
loaders = LoggedChangeLoaders.new(session)
|
61
|
-
|
62
79
|
success = false
|
63
80
|
begin
|
64
81
|
replicator # ensure that replicator is created and has chance to validate settings
|
65
82
|
|
66
83
|
loop do
|
67
84
|
begin
|
68
|
-
|
69
|
-
diff = ReplicationDifference.new loaders
|
70
|
-
diff.load
|
85
|
+
diff = load_difference
|
71
86
|
break unless diff.loaded?
|
72
87
|
break if sweeper.terminated?
|
73
88
|
if diff.type != :no_diff and not event_filtered?(diff)
|
74
89
|
replicator.replicate_difference diff
|
75
90
|
end
|
76
91
|
rescue Exception => e
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
#
|
82
|
-
|
92
|
+
if e.message =~ /violates foreign key constraint|foreign key constraint fails/i and !diff.second_chance?
|
93
|
+
# Note:
|
94
|
+
# Identifying the foreign key constraint violation via regular expression is
|
95
|
+
# database dependent and *dirty*.
|
96
|
+
# It would be better to use the ActiveRecord #translate_exception mechanism.
|
97
|
+
# However as per version 3.0.5 this doesn't work yet properly.
|
98
|
+
|
99
|
+
diff.second_chance = true
|
100
|
+
second_chancers << diff
|
101
|
+
else
|
102
|
+
begin
|
103
|
+
helper.log_replication_outcome diff, e.message,
|
104
|
+
e.class.to_s + "\n" + e.backtrace.join("\n")
|
105
|
+
rescue Exception => _
|
106
|
+
# if logging to database itself fails, re-raise the original exception
|
107
|
+
raise e
|
108
|
+
end
|
83
109
|
end
|
84
110
|
end
|
85
111
|
end
|
@@ -2,6 +2,12 @@ $LOAD_PATH.unshift File.dirname(__FILE__) + '/../lib'
|
|
2
2
|
|
3
3
|
require 'optparse'
|
4
4
|
require 'thread'
|
5
|
+
require 'monitor'
|
6
|
+
|
7
|
+
class Monitor
|
8
|
+
alias lock mon_enter
|
9
|
+
alias unlock mon_exit
|
10
|
+
end
|
5
11
|
|
6
12
|
module RR
|
7
13
|
# This class implements the functionality of the 'replicate' command.
|
@@ -94,7 +100,7 @@ EOS
|
|
94
100
|
# Initializes the waiter thread used for replication pauses and processing
|
95
101
|
# the process TERM signal.
|
96
102
|
def init_waiter
|
97
|
-
@termination_mutex =
|
103
|
+
@termination_mutex = Monitor.new
|
98
104
|
@termination_mutex.lock
|
99
105
|
@waiter_thread ||= Thread.new {@termination_mutex.lock; self.termination_requested = true}
|
100
106
|
%w(TERM INT).each do |signal|
|
@@ -19,7 +19,15 @@ module RR
|
|
19
19
|
return 1 unless left_row
|
20
20
|
rank = 0
|
21
21
|
primary_key_names.any? do |key|
|
22
|
-
|
22
|
+
if left_row[key].kind_of?(String)
|
23
|
+
# When databases order strings, then 'a' < 'A' while for Ruby 'A' < 'a'
|
24
|
+
# ==> Use a combination of case sensitive and case insensitive comparing to
|
25
|
+
# reproduce the database behaviour.
|
26
|
+
rank = left_row[key].casecmp(right_row[key]) # deal with 'a' to 'B' comparisons
|
27
|
+
rank = -(left_row[key] <=> right_row[key]) if rank == 0 # deal with 'a' to 'A' comparisons
|
28
|
+
else
|
29
|
+
rank = left_row[key] <=> right_row[key]
|
30
|
+
end
|
23
31
|
rank != 0
|
24
32
|
end
|
25
33
|
rank
|
data/lib/rubyrep/version.rb
CHANGED
@@ -1,3 +1,4 @@
|
|
1
|
+
|
1
2
|
require 'rake'
|
2
3
|
require 'benchmark'
|
3
4
|
|
@@ -136,7 +137,7 @@ def populate_rep_data
|
|
136
137
|
# Updating progress bar
|
137
138
|
progress_bar.step
|
138
139
|
|
139
|
-
database = [:left, :right]
|
140
|
+
database = [:left, :right][rand(2)]
|
140
141
|
|
141
142
|
case rand(100)
|
142
143
|
when 0...BIG_REP_INSERT
|
@@ -147,7 +148,7 @@ def populate_rep_data
|
|
147
148
|
next_id += 1
|
148
149
|
session.send(database).insert_record 'big_rep', attributes
|
149
150
|
when BIG_REP_INSERT...BIG_REP_UPDATE
|
150
|
-
id = all_ids[database].
|
151
|
+
id = all_ids[database][rand(all_ids[database].size)]
|
151
152
|
attributes = session.send(database).select_one("select * from big_rep where id = '#{id}'")
|
152
153
|
column = number_columns[rand(number_columns.size)]
|
153
154
|
attributes[column] = rand(1000)
|
@@ -10,9 +10,13 @@ describe ConnectionExtenders do
|
|
10
10
|
it "db_connect should install the already created logger" do
|
11
11
|
configuration = deep_copy(Initializer.configuration)
|
12
12
|
io = StringIO.new
|
13
|
-
logger =
|
13
|
+
logger = ActiveSupport::BufferedLogger.new(io)
|
14
14
|
configuration.left[:logger] = logger
|
15
15
|
session = Session.new configuration
|
16
|
+
|
17
|
+
session.left.connection.instance_eval {@logger}.should == logger
|
18
|
+
session.right.connection.instance_eval {@logger}.should_not == logger
|
19
|
+
|
16
20
|
session.left.select_one "select 'left_query'"
|
17
21
|
session.right.select_one "select 'right_query'"
|
18
22
|
|
@@ -9,7 +9,7 @@ describe ProxyConnection do
|
|
9
9
|
end
|
10
10
|
|
11
11
|
it "initialize should connect to the database" do
|
12
|
-
|
12
|
+
(!!@connection.connection.active?).should == true
|
13
13
|
end
|
14
14
|
|
15
15
|
it "initialize should store the configuratin" do
|
@@ -17,9 +17,21 @@ describe ProxyConnection do
|
|
17
17
|
end
|
18
18
|
|
19
19
|
it "destroy should disconnect from the database" do
|
20
|
+
if ActiveSupport.const_defined?(:Notifications)
|
21
|
+
ConnectionExtenders::install_logger @connection.connection, :logger => StringIO.new
|
22
|
+
log_subscriber = @connection.connection.log_subscriber
|
23
|
+
|
24
|
+
ActiveSupport::Notifications.notifier.listeners_for("sql.active_record").should include(log_subscriber)
|
25
|
+
end
|
26
|
+
|
20
27
|
@connection.destroy
|
21
28
|
|
22
|
-
|
29
|
+
if ActiveSupport.const_defined?(:Notifications)
|
30
|
+
ActiveSupport::Notifications.notifier.listeners_for("sql.active_record").should_not include(log_subscriber)
|
31
|
+
@connection.connection.log_subscriber.should be_nil
|
32
|
+
end
|
33
|
+
|
34
|
+
(!!@connection.connection.active?).should == false
|
23
35
|
end
|
24
36
|
|
25
37
|
it "cursors should return the current cursor hash or an empty hash if nil" do
|
@@ -135,6 +135,68 @@ describe ReplicationRun do
|
|
135
135
|
end
|
136
136
|
end
|
137
137
|
|
138
|
+
it "run should replication records with foreign key constraints" do
|
139
|
+
begin
|
140
|
+
config = deep_copy(standard_config)
|
141
|
+
config.options[:committer] = :never_commit
|
142
|
+
|
143
|
+
session = Session.new(config)
|
144
|
+
|
145
|
+
session.left.insert_record 'referencing_table', {
|
146
|
+
'id' => '5',
|
147
|
+
}
|
148
|
+
session.left.insert_record 'rr_pending_changes', {
|
149
|
+
'change_table' => 'referencing_table',
|
150
|
+
'change_key' => 'id|5',
|
151
|
+
'change_type' => 'I',
|
152
|
+
'change_time' => Time.now
|
153
|
+
}
|
154
|
+
|
155
|
+
session.left.insert_record 'referenced_table2', {
|
156
|
+
'id' => '6',
|
157
|
+
}
|
158
|
+
session.left.insert_record 'rr_pending_changes', {
|
159
|
+
'change_table' => 'referenced_table2',
|
160
|
+
'change_key' => 'id|6',
|
161
|
+
'change_type' => 'I',
|
162
|
+
'change_time' => Time.now
|
163
|
+
}
|
164
|
+
|
165
|
+
session.left.update_record 'referencing_table', {
|
166
|
+
'id' => 5,
|
167
|
+
'third_fk' => '6'
|
168
|
+
}
|
169
|
+
session.left.insert_record 'rr_pending_changes', {
|
170
|
+
'change_table' => 'referencing_table',
|
171
|
+
'change_key' => 'id|5',
|
172
|
+
'change_new_key' => 'id|5',
|
173
|
+
'change_type' => 'U',
|
174
|
+
'change_time' => Time.now
|
175
|
+
}
|
176
|
+
|
177
|
+
run = ReplicationRun.new session, TaskSweeper.new(1)
|
178
|
+
run.run
|
179
|
+
|
180
|
+
session.right.select_record(:table => "referencing_table", :from => {'id' => 5}).should == {
|
181
|
+
'id' => 5,
|
182
|
+
'first_fk' => nil,
|
183
|
+
'second_fk' => nil,
|
184
|
+
'third_fk' => 6
|
185
|
+
}
|
186
|
+
ensure
|
187
|
+
Committers::NeverCommitter.rollback_current_session
|
188
|
+
if session
|
189
|
+
session.left.execute "delete from referencing_table where id = 5"
|
190
|
+
session.left.execute "delete from referenced_table2 where id = 6"
|
191
|
+
|
192
|
+
session.right.execute "delete from referencing_table where id = 5"
|
193
|
+
session.right.execute "delete from referenced_table2 where id = 6"
|
194
|
+
|
195
|
+
session.left.execute "delete from rr_pending_changes"
|
196
|
+
end
|
197
|
+
end
|
198
|
+
end
|
199
|
+
|
138
200
|
it "run should not replicate filtered changes" do
|
139
201
|
begin
|
140
202
|
config = deep_copy(standard_config)
|
@@ -13,6 +13,13 @@ describe TableScanHelper do
|
|
13
13
|
@scan.rank_rows({'first_id' => 1, 'second_id' => 1}, {'first_id' => 1, 'second_id' => 1}).should == 0
|
14
14
|
@scan.rank_rows({'first_id' => 1, 'second_id' => 1}, {'first_id' => 1, 'second_id' => 2}).should == -1
|
15
15
|
@scan.rank_rows({'first_id' => 2, 'second_id' => 1}, {'first_id' => 1, 'second_id' => 1}).should == 1
|
16
|
+
|
17
|
+
# should rank strings according to database logic ('a' < 'A')
|
18
|
+
# instead of the Ruby logic (which is the other way round)
|
19
|
+
@scan.rank_rows({'first_id' => 'a', 'second_id' => 1}, {'first_id' => 'B', 'second_id' => 1}).should == -1
|
20
|
+
@scan.rank_rows({'first_id' => 'a', 'second_id' => 1}, {'first_id' => 'A', 'second_id' => 1}).should == -1
|
21
|
+
@scan.rank_rows({'first_id' => 'a', 'second_id' => 1}, {'first_id' => 'a', 'second_id' => 1}).should == 0
|
22
|
+
|
16
23
|
lambda {@scan.rank_rows(nil,nil)}.should raise_error(RuntimeError, 'At least one of left_row and right_row must not be nil!')
|
17
24
|
@scan.rank_rows(nil, {'first_id' => 1, 'second_id' => 1}).should == 1
|
18
25
|
@scan.rank_rows({'first_id' => 1, 'second_id' => 1}, nil).should == -1
|
data/tasks/database.rake
CHANGED
@@ -18,7 +18,7 @@ def create_database(config)
|
|
18
18
|
@charset = ENV['CHARSET'] || 'utf8'
|
19
19
|
@collation = ENV['COLLATION'] || 'utf8_general_ci'
|
20
20
|
begin
|
21
|
-
connection = RR::ConnectionExtenders.db_connect(config.merge({
|
21
|
+
connection = RR::ConnectionExtenders.db_connect(config.merge({:database => nil}))
|
22
22
|
connection.create_database(config[:database], {:charset => @charset, :collation => @collation})
|
23
23
|
RR::ConnectionExtenders.db_connect(config)
|
24
24
|
rescue
|
data/tasks/rspec.rake
CHANGED
@@ -41,18 +41,14 @@ namespace :spec do
|
|
41
41
|
desc "Run the specs for all supported databases"
|
42
42
|
task :all_dbs do
|
43
43
|
[:postgres, :mysql].each do |test_db|
|
44
|
-
puts "Running specs for #{test_db
|
45
|
-
|
46
|
-
system "spec spec"
|
44
|
+
puts "Running specs for #{test_db}"
|
45
|
+
system "bash -c 'RR_TEST_DB=#{test_db} spec spec'"
|
47
46
|
end
|
48
47
|
end
|
49
48
|
|
50
49
|
desc "Run the specs for all supported databases and ruby platforms"
|
51
50
|
task :all_rubies do
|
52
|
-
|
53
|
-
system "rake spec:all_dbs"
|
54
|
-
puts "Running spec:all_dbs in jruby"
|
55
|
-
system "export PATH=#{JRUBY_HOME}/bin:$PATH; rake spec:all_dbs"
|
51
|
+
system %(rvm exec bash -c 'for db in postgres mysql; do echo "`rvm current` - $db:"; RR_TEST_DB=$db spec spec; done')
|
56
52
|
end
|
57
53
|
|
58
54
|
begin
|
metadata
CHANGED
@@ -1,12 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rubyrep
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
|
4
|
+
hash: 31
|
5
|
+
prerelease:
|
5
6
|
segments:
|
6
7
|
- 1
|
7
|
-
- 1
|
8
8
|
- 2
|
9
|
-
|
9
|
+
- 0
|
10
|
+
version: 1.2.0
|
10
11
|
platform: ruby
|
11
12
|
authors:
|
12
13
|
- Arndt Lehmann
|
@@ -14,53 +15,60 @@ autorequire:
|
|
14
15
|
bindir: bin
|
15
16
|
cert_chain: []
|
16
17
|
|
17
|
-
date:
|
18
|
+
date: 2011-03-07 00:00:00 +09:00
|
18
19
|
default_executable:
|
19
20
|
dependencies:
|
20
21
|
- !ruby/object:Gem::Dependency
|
21
22
|
name: activesupport
|
22
23
|
prerelease: false
|
23
24
|
requirement: &id001 !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
24
26
|
requirements:
|
25
27
|
- - ">="
|
26
28
|
- !ruby/object:Gem::Version
|
29
|
+
hash: 13
|
27
30
|
segments:
|
28
|
-
- 2
|
29
31
|
- 3
|
32
|
+
- 0
|
30
33
|
- 5
|
31
|
-
version:
|
34
|
+
version: 3.0.5
|
32
35
|
type: :runtime
|
33
36
|
version_requirements: *id001
|
34
37
|
- !ruby/object:Gem::Dependency
|
35
38
|
name: activerecord
|
36
39
|
prerelease: false
|
37
40
|
requirement: &id002 !ruby/object:Gem::Requirement
|
41
|
+
none: false
|
38
42
|
requirements:
|
39
43
|
- - ">="
|
40
44
|
- !ruby/object:Gem::Version
|
45
|
+
hash: 13
|
41
46
|
segments:
|
42
|
-
- 2
|
43
47
|
- 3
|
48
|
+
- 0
|
44
49
|
- 5
|
45
|
-
version:
|
50
|
+
version: 3.0.5
|
46
51
|
type: :runtime
|
47
52
|
version_requirements: *id002
|
48
53
|
- !ruby/object:Gem::Dependency
|
49
54
|
name: hoe
|
50
55
|
prerelease: false
|
51
56
|
requirement: &id003 !ruby/object:Gem::Requirement
|
57
|
+
none: false
|
52
58
|
requirements:
|
53
59
|
- - ">="
|
54
60
|
- !ruby/object:Gem::Version
|
61
|
+
hash: 41
|
55
62
|
segments:
|
56
63
|
- 2
|
57
|
-
-
|
58
|
-
-
|
59
|
-
version: 2.
|
64
|
+
- 9
|
65
|
+
- 1
|
66
|
+
version: 2.9.1
|
60
67
|
type: :development
|
61
68
|
version_requirements: *id003
|
62
|
-
description:
|
63
|
-
email:
|
69
|
+
description: ""
|
70
|
+
email:
|
71
|
+
- mail@arndtlehman.com
|
64
72
|
executables:
|
65
73
|
- rubyrep
|
66
74
|
extensions: []
|
@@ -222,8 +230,9 @@ files:
|
|
222
230
|
- tasks/stats.rake
|
223
231
|
- tasks/task_helper.rb
|
224
232
|
- tasks/website.rake
|
233
|
+
- .gemtest
|
225
234
|
has_rdoc: true
|
226
|
-
homepage:
|
235
|
+
homepage:
|
227
236
|
licenses: []
|
228
237
|
|
229
238
|
post_install_message:
|
@@ -233,25 +242,29 @@ rdoc_options:
|
|
233
242
|
require_paths:
|
234
243
|
- lib
|
235
244
|
required_ruby_version: !ruby/object:Gem::Requirement
|
245
|
+
none: false
|
236
246
|
requirements:
|
237
247
|
- - ">="
|
238
248
|
- !ruby/object:Gem::Version
|
249
|
+
hash: 3
|
239
250
|
segments:
|
240
251
|
- 0
|
241
252
|
version: "0"
|
242
253
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
254
|
+
none: false
|
243
255
|
requirements:
|
244
256
|
- - ">="
|
245
257
|
- !ruby/object:Gem::Version
|
258
|
+
hash: 3
|
246
259
|
segments:
|
247
260
|
- 0
|
248
261
|
version: "0"
|
249
262
|
requirements: []
|
250
263
|
|
251
264
|
rubyforge_project: rubyrep
|
252
|
-
rubygems_version: 1.
|
265
|
+
rubygems_version: 1.5.2
|
253
266
|
signing_key:
|
254
267
|
specification_version: 3
|
255
|
-
summary:
|
268
|
+
summary: ""
|
256
269
|
test_files: []
|
257
270
|
|