rubyrep 1.0.7 → 1.0.8
Sign up to get free protection for your applications and to get access to all the features.
- data/History.txt +8 -0
- data/Manifest.txt +2 -0
- data/lib/rubyrep/committers/buffered_committer.rb +6 -0
- data/lib/rubyrep/committers/committers.rb +6 -0
- data/lib/rubyrep/configuration.rb +7 -1
- data/lib/rubyrep/proxy_connection.rb +18 -5
- data/lib/rubyrep/replication_helper.rb +6 -0
- data/lib/rubyrep/replication_initializer.rb +33 -25
- data/lib/rubyrep/replication_run.rb +21 -6
- data/lib/rubyrep/replication_runner.rb +25 -9
- data/lib/rubyrep/replicators/two_way_replicator.rb +46 -30
- data/lib/rubyrep/session.rb +16 -5
- data/lib/rubyrep/uninstall_runner.rb +1 -0
- data/lib/rubyrep/version.rb +1 -1
- data/rubyrep +8 -0
- data/rubyrep.bat +4 -0
- data/sims/performance/performance.rake +9 -9
- data/spec/buffered_committer_spec.rb +6 -3
- data/spec/committers_spec.rb +4 -0
- data/spec/proxy_connection_spec.rb +27 -0
- data/spec/replication_extender_interface_spec.rb +7 -5
- data/spec/replication_helper_spec.rb +9 -0
- data/spec/replication_initializer_spec.rb +10 -0
- data/spec/replication_run_spec.rb +70 -0
- data/spec/replication_runner_spec.rb +31 -0
- data/spec/session_spec.rb +18 -0
- data/spec/spec_helper.rb +2 -2
- data/spec/two_way_replicator_spec.rb +94 -0
- data/spec/uninstall_runner_spec.rb +20 -13
- data/tasks/java.rake +0 -20
- data.tar.gz.sig +0 -0
- metadata +4 -2
- metadata.gz.sig +0 -0
data/History.txt
CHANGED
@@ -1,3 +1,11 @@
|
|
1
|
+
== 1.0.8 2009-10-01
|
2
|
+
|
3
|
+
* Feature: replication more robust against connection failures
|
4
|
+
* Feature: initial syncs before replication can be disabled with :initial_sync option
|
5
|
+
* Bug fix: better detection of failed update and delete replications
|
6
|
+
* Bug fix: fix scenario where replication could be logged as successful even when failed
|
7
|
+
* Bug fix: make proxied replication work under JRuby
|
8
|
+
|
1
9
|
== 1.0.7 2009-07-26
|
2
10
|
|
3
11
|
* Bug fix: buffered LoggedChangeLoader#update to avoid timeouts with large replication backlogs.
|
data/Manifest.txt
CHANGED
@@ -89,6 +89,12 @@ module RR
|
|
89
89
|
end
|
90
90
|
end
|
91
91
|
|
92
|
+
# Returns +true+ if a new transaction was started since the last
|
93
|
+
# insert / update / delete.
|
94
|
+
def new_transaction?
|
95
|
+
@change_counter == 0
|
96
|
+
end
|
97
|
+
|
92
98
|
# A new committer is created for each table sync.
|
93
99
|
# * session: a Session object representing the current database session
|
94
100
|
def initialize(session)
|
@@ -68,6 +68,12 @@ module RR
|
|
68
68
|
self.session = session
|
69
69
|
self.connections = {:left => session.left, :right => session.right}
|
70
70
|
end
|
71
|
+
|
72
|
+
# Returns +true+ if a new transaction was started since the last
|
73
|
+
# insert / update / delete.
|
74
|
+
def new_transaction?
|
75
|
+
false
|
76
|
+
end
|
71
77
|
|
72
78
|
# Inserts the specified record in the specified +database+ (either :left or :right).
|
73
79
|
# +table+ is the name of the target table.
|
@@ -30,6 +30,7 @@ module RR
|
|
30
30
|
:table_ordering => true,
|
31
31
|
:scan_progress_printer => :progress_bar,
|
32
32
|
:use_ansi => true_if_running_in_a_terminal_and_not_under_windows,
|
33
|
+
:initial_sync => true,
|
33
34
|
:adjust_sequences => true,
|
34
35
|
:sequence_adjustment_buffer => 0,
|
35
36
|
:sequence_increment => 2,
|
@@ -98,8 +99,13 @@ module RR
|
|
98
99
|
# used for the initial sync of a table.)
|
99
100
|
# If no +:syncer+ option is specified, than a syncer as named by this
|
100
101
|
# option is used.
|
102
|
+
# * :+initial_sync+:
|
103
|
+
# If +true+, syncs a table when initializing replication.
|
104
|
+
# Disable with care!
|
105
|
+
# (I. e. ensure that the table(s) have indeed same data in both databases
|
106
|
+
# before starting replication.)
|
101
107
|
# * :+adjust_sequences+:
|
102
|
-
# If true
|
108
|
+
# If +true+, adjust sequences to avoid number conflicts between left and
|
103
109
|
# right database during replication.
|
104
110
|
# * :+sequence_adjustement_buffer+:
|
105
111
|
# When updating a sequence, this is the additional gap to avoid sequence
|
@@ -93,6 +93,10 @@ module RR
|
|
93
93
|
# This class represents a remote activerecord database connection.
|
94
94
|
# Normally created by DatabaseProxy
|
95
95
|
class ProxyConnection
|
96
|
+
# Ensure that the proxy object always stays on server side and only remote
|
97
|
+
# references are returned to the client.
|
98
|
+
include DRbUndumped
|
99
|
+
|
96
100
|
extend Forwardable
|
97
101
|
|
98
102
|
# The database connection
|
@@ -105,14 +109,14 @@ module RR
|
|
105
109
|
def_delegators :connection,
|
106
110
|
:columns, :quote_column_name,
|
107
111
|
:quote_table_name, :execute,
|
108
|
-
:select_one, :select_all, :tables,
|
112
|
+
:select_one, :select_all, :tables, :update, :delete,
|
109
113
|
:begin_db_transaction, :rollback_db_transaction, :commit_db_transaction,
|
110
114
|
:referenced_tables,
|
111
115
|
:create_or_replace_replication_trigger_function,
|
112
116
|
:create_replication_trigger, :drop_replication_trigger, :replication_trigger_exists?,
|
113
117
|
:sequence_values, :update_sequences, :clear_sequence_setup,
|
114
|
-
:
|
115
|
-
|
118
|
+
:drop_table, :add_big_primary_key, :add_column, :remove_column
|
119
|
+
|
116
120
|
# Caching the primary keys. This is a hash with
|
117
121
|
# * key: table name
|
118
122
|
# * value: array of primary key names
|
@@ -155,6 +159,13 @@ module RR
|
|
155
159
|
result
|
156
160
|
end
|
157
161
|
|
162
|
+
# Creates a table
|
163
|
+
# Call forwarded to ActiveRecord::ConnectionAdapters::SchemaStatements#create_table
|
164
|
+
# Provides an empty block (to prevent DRB from calling back the client)
|
165
|
+
def create_table(*params)
|
166
|
+
connection.create_table(*params) {}
|
167
|
+
end
|
168
|
+
|
158
169
|
# Returns a Hash of currently registerred cursors
|
159
170
|
def cursors
|
160
171
|
@cursors ||= {}
|
@@ -361,8 +372,9 @@ module RR
|
|
361
372
|
# * +org_key+:
|
362
373
|
# A hash of column_name => value pairs. If +nil+, use the key specified by
|
363
374
|
# +values+ instead.
|
375
|
+
# Returns the number of modified records.
|
364
376
|
def update_record(table, values, org_key = nil)
|
365
|
-
|
377
|
+
update table_update_query(table, values, org_key)
|
366
378
|
end
|
367
379
|
|
368
380
|
# Returns an SQL delete query for the given +table+ and +values+
|
@@ -379,8 +391,9 @@ module RR
|
|
379
391
|
# Deletes the specified record from the named +table+.
|
380
392
|
# +values+ is a hash of column_name => value pairs. (Only the primary key
|
381
393
|
# values will be used and must be included in the hash.)
|
394
|
+
# Returns the number of deleted records.
|
382
395
|
def delete_record(table, values)
|
383
|
-
|
396
|
+
delete table_delete_query(table, values)
|
384
397
|
end
|
385
398
|
end
|
386
399
|
end
|
@@ -19,6 +19,12 @@ module RR
|
|
19
19
|
# Delegates to Session#corresponding_table
|
20
20
|
def corresponding_table(db_arm, table); session.corresponding_table(db_arm, table); end
|
21
21
|
|
22
|
+
# Returns +true+ if a new transaction was started since the last
|
23
|
+
# insert / update / delete.
|
24
|
+
def new_transaction?
|
25
|
+
committer.new_transaction?
|
26
|
+
end
|
27
|
+
|
22
28
|
# Delegates to Committer#insert_record
|
23
29
|
def insert_record(database, table, values)
|
24
30
|
committer.insert_record(database, table, values)
|
@@ -149,19 +149,20 @@ module RR
|
|
149
149
|
# Creates the replication log table.
|
150
150
|
def create_event_log
|
151
151
|
silence_ddl_notices(:left) do
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
session.left.
|
152
|
+
table_name = "#{options[:rep_prefix]}_logged_events"
|
153
|
+
session.left.create_table "#{options[:rep_prefix]}_logged_events"
|
154
|
+
session.left.add_column table_name, :activity, :string
|
155
|
+
session.left.add_column table_name, :change_table, :string
|
156
|
+
session.left.add_column table_name, :diff_type, :string
|
157
|
+
session.left.add_column table_name, :change_key, :string
|
158
|
+
session.left.add_column table_name, :left_change_type, :string
|
159
|
+
session.left.add_column table_name, :right_change_type, :string
|
160
|
+
session.left.add_column table_name, :description, :string, :limit => DESCRIPTION_SIZE
|
161
|
+
session.left.add_column table_name, :long_description, :string, :limit => LONG_DESCRIPTION_SIZE
|
162
|
+
session.left.add_column table_name, :event_time, :timestamp
|
163
|
+
session.left.add_column table_name, :diff_dump, :string, :limit => DIFF_DUMP_SIZE
|
164
|
+
session.left.remove_column table_name, 'id'
|
165
|
+
session.left.add_big_primary_key table_name, 'id'
|
165
166
|
end
|
166
167
|
end
|
167
168
|
|
@@ -169,14 +170,16 @@ module RR
|
|
169
170
|
# * database: either :+left+ or :+right+
|
170
171
|
def create_change_log(database)
|
171
172
|
silence_ddl_notices(database) do
|
172
|
-
session.send(database)
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
173
|
+
connection = session.send(database)
|
174
|
+
table_name = "#{options[:rep_prefix]}_pending_changes"
|
175
|
+
connection.create_table table_name
|
176
|
+
connection.add_column table_name, :change_table, :string
|
177
|
+
connection.add_column table_name, :change_key, :string
|
178
|
+
connection.add_column table_name, :change_new_key, :string
|
179
|
+
connection.add_column table_name, :change_type, :string
|
180
|
+
connection.add_column table_name, :change_time, :timestamp
|
181
|
+
connection.remove_column table_name, 'id'
|
182
|
+
connection.add_big_primary_key table_name, 'id'
|
180
183
|
end
|
181
184
|
end
|
182
185
|
|
@@ -190,9 +193,12 @@ module RR
|
|
190
193
|
def ensure_activity_markers
|
191
194
|
table_name = "#{options[:rep_prefix]}_running_flags"
|
192
195
|
[:left, :right].each do |database|
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
+
connection = session.send(database)
|
197
|
+
unless connection.tables.include? table_name
|
198
|
+
silence_ddl_notices(database) do
|
199
|
+
connection.create_table table_name
|
200
|
+
connection.add_column table_name, :active, :integer
|
201
|
+
connection.remove_column table_name, 'id'
|
196
202
|
end
|
197
203
|
end
|
198
204
|
end
|
@@ -298,7 +304,9 @@ module RR
|
|
298
304
|
unsynced = true
|
299
305
|
end
|
300
306
|
end
|
301
|
-
|
307
|
+
if unsynced and table_options[:initial_sync]
|
308
|
+
unsynced_table_pairs << table_pair
|
309
|
+
end
|
302
310
|
end
|
303
311
|
unsynced_table_specs = unsynced_table_pairs.map do |table_pair|
|
304
312
|
"#{table_pair[:left]}, #{table_pair[:right]}"
|
@@ -35,10 +35,15 @@ module RR
|
|
35
35
|
changes_pending
|
36
36
|
end
|
37
37
|
|
38
|
+
# Apparently sometimes above check for changes takes already so long, that
|
39
|
+
# the replication run times out.
|
40
|
+
# Check for this and if timed out, return (silently).
|
41
|
+
return if sweeper.terminated?
|
42
|
+
|
38
43
|
loaders = LoggedChangeLoaders.new(session)
|
39
44
|
|
45
|
+
success = false
|
40
46
|
begin
|
41
|
-
success = false
|
42
47
|
replicator # ensure that replicator is created and has chance to validate settings
|
43
48
|
|
44
49
|
loop do
|
@@ -47,16 +52,26 @@ module RR
|
|
47
52
|
diff = ReplicationDifference.new loaders
|
48
53
|
diff.load
|
49
54
|
break unless diff.loaded?
|
50
|
-
|
55
|
+
break if sweeper.terminated?
|
51
56
|
replicator.replicate_difference diff if diff.type != :no_diff
|
52
57
|
rescue Exception => e
|
53
|
-
|
54
|
-
|
58
|
+
begin
|
59
|
+
helper.log_replication_outcome diff, e.message,
|
60
|
+
e.class.to_s + "\n" + e.backtrace.join("\n")
|
61
|
+
rescue Exception => _
|
62
|
+
# if logging to database itself fails, re-raise the original exception
|
63
|
+
raise e
|
64
|
+
end
|
55
65
|
end
|
56
66
|
end
|
57
|
-
success = true
|
67
|
+
success = true
|
58
68
|
ensure
|
59
|
-
|
69
|
+
if sweeper.terminated?
|
70
|
+
helper.finalize false
|
71
|
+
session.disconnect_databases
|
72
|
+
else
|
73
|
+
helper.finalize success
|
74
|
+
end
|
60
75
|
end
|
61
76
|
end
|
62
77
|
|
@@ -65,12 +65,20 @@ EOS
|
|
65
65
|
# Loads config file and creates session if necessary.
|
66
66
|
def session
|
67
67
|
unless @session
|
68
|
-
|
69
|
-
|
68
|
+
unless @config
|
69
|
+
load options[:config_file]
|
70
|
+
@config = Initializer.configuration
|
71
|
+
end
|
72
|
+
@session = Session.new @config
|
70
73
|
end
|
71
74
|
@session
|
72
75
|
end
|
73
76
|
|
77
|
+
# Removes current +Session+.
|
78
|
+
def clear_session
|
79
|
+
@session = nil
|
80
|
+
end
|
81
|
+
|
74
82
|
# Wait for the next replication time
|
75
83
|
def pause_replication
|
76
84
|
@last_run ||= 1.year.ago
|
@@ -100,6 +108,20 @@ EOS
|
|
100
108
|
initializer.prepare_replication
|
101
109
|
end
|
102
110
|
|
111
|
+
# Executes a single replication run
|
112
|
+
def execute_once
|
113
|
+
session.refresh
|
114
|
+
timeout = session.configuration.options[:database_connection_timeout]
|
115
|
+
terminated = TaskSweeper.timeout(timeout) do |sweeper|
|
116
|
+
run = ReplicationRun.new session, sweeper
|
117
|
+
run.run
|
118
|
+
end.terminated?
|
119
|
+
raise "replication run timed out" if terminated
|
120
|
+
rescue Exception => e
|
121
|
+
clear_session
|
122
|
+
raise e
|
123
|
+
end
|
124
|
+
|
103
125
|
# Executes an endless loop of replication runs
|
104
126
|
def execute
|
105
127
|
init_waiter
|
@@ -107,13 +129,7 @@ EOS
|
|
107
129
|
|
108
130
|
until termination_requested do
|
109
131
|
begin
|
110
|
-
|
111
|
-
timeout = session.configuration.options[:database_connection_timeout]
|
112
|
-
terminated = TaskSweeper.timeout(timeout) do |sweeper|
|
113
|
-
run = ReplicationRun.new session, sweeper
|
114
|
-
run.run
|
115
|
-
end.terminated?
|
116
|
-
raise "replication run timed out" if terminated
|
132
|
+
execute_once
|
117
133
|
rescue Exception => e
|
118
134
|
now = Time.now.iso8601
|
119
135
|
$stderr.puts "#{now} Exception caught: #{e}"
|
@@ -227,19 +227,9 @@ module RR
|
|
227
227
|
diff.amend
|
228
228
|
replicate_difference diff, remaining_attempts - 1, "source record for insert vanished"
|
229
229
|
else
|
230
|
-
|
231
|
-
# note: savepoints have to be used for postgresql (as a failed SQL
|
232
|
-
# statement will otherwise invalidate the complete transaction.)
|
233
|
-
rep_helper.session.send(target_db).execute "savepoint rr_insert"
|
234
|
-
log_replication_outcome source_db, diff
|
230
|
+
attempt_change('insert', source_db, target_db, diff, remaining_attempts) do
|
235
231
|
rep_helper.insert_record target_db, target_table, values
|
236
|
-
|
237
|
-
rep_helper.session.send(target_db).execute "rollback to savepoint rr_insert"
|
238
|
-
row = rep_helper.load_record target_db, target_table, source_key
|
239
|
-
raise unless row # problem is not the existence of the record in the target db
|
240
|
-
diff.amend
|
241
|
-
replicate_difference diff, remaining_attempts - 1,
|
242
|
-
"insert failed with #{e.message}"
|
232
|
+
log_replication_outcome source_db, diff
|
243
233
|
end
|
244
234
|
end
|
245
235
|
end
|
@@ -263,19 +253,45 @@ module RR
|
|
263
253
|
diff.amend
|
264
254
|
replicate_difference diff, remaining_attempts - 1, "source record for update vanished"
|
265
255
|
else
|
266
|
-
|
267
|
-
rep_helper.
|
268
|
-
|
269
|
-
|
270
|
-
|
271
|
-
|
272
|
-
|
273
|
-
|
274
|
-
"update failed with #{e.message}"
|
256
|
+
attempt_change('update', source_db, target_db, diff, remaining_attempts) do
|
257
|
+
number_updated = rep_helper.update_record target_db, target_table, values, target_key
|
258
|
+
if number_updated == 0
|
259
|
+
diff.amend
|
260
|
+
replicate_difference diff, remaining_attempts - 1, "target record for update vanished"
|
261
|
+
else
|
262
|
+
log_replication_outcome source_db, diff
|
263
|
+
end
|
275
264
|
end
|
276
265
|
end
|
277
266
|
end
|
278
267
|
|
268
|
+
# Helper for execution of insert / update / delete attempts.
|
269
|
+
# Wraps those attempts into savepoints and handles exceptions.
|
270
|
+
#
|
271
|
+
# Note:
|
272
|
+
# Savepoints have to be used for PostgreSQL (as a failed SQL statement
|
273
|
+
# will otherwise invalidate the complete transaction.)
|
274
|
+
#
|
275
|
+
# * +action+: short description of change (e. g.: "update" or "delete")
|
276
|
+
# * +source_db+: either :+left+ or :+right+ - source database of replication
|
277
|
+
# * +target_db+: either :+left+ or :+right+ - target database of replication
|
278
|
+
# * +diff+: the current ReplicationDifference instance
|
279
|
+
# * +remaining_attempts+: the number of remaining replication attempts for this difference
|
280
|
+
def attempt_change(action, source_db, target_db, diff, remaining_attempts)
|
281
|
+
begin
|
282
|
+
rep_helper.session.send(target_db).execute "savepoint rr_#{action}_#{remaining_attempts}"
|
283
|
+
yield
|
284
|
+
unless rep_helper.new_transaction?
|
285
|
+
rep_helper.session.send(target_db).execute "release savepoint rr_#{action}_#{remaining_attempts}"
|
286
|
+
end
|
287
|
+
rescue Exception => e
|
288
|
+
rep_helper.session.send(target_db).execute "rollback to savepoint rr_#{action}_#{remaining_attempts}"
|
289
|
+
diff.amend
|
290
|
+
replicate_difference diff, remaining_attempts - 1,
|
291
|
+
"#{action} failed with #{e.message}"
|
292
|
+
end
|
293
|
+
end
|
294
|
+
|
279
295
|
# Attempts to delete the source record from the target database.
|
280
296
|
# E. g. if +source_db is :+left+, then the record is deleted in database
|
281
297
|
# :+right+.
|
@@ -287,15 +303,15 @@ module RR
|
|
287
303
|
change = diff.changes[source_db]
|
288
304
|
target_db = OTHER_SIDE[source_db]
|
289
305
|
target_table = rep_helper.corresponding_table(source_db, change.table)
|
290
|
-
|
291
|
-
|
292
|
-
|
293
|
-
|
294
|
-
|
295
|
-
|
296
|
-
|
297
|
-
|
298
|
-
|
306
|
+
|
307
|
+
attempt_change('delete', source_db, target_db, diff, remaining_attempts) do
|
308
|
+
number_updated = rep_helper.delete_record target_db, target_table, target_key
|
309
|
+
if number_updated == 0
|
310
|
+
diff.amend
|
311
|
+
replicate_difference diff, remaining_attempts - 1, "target record for delete vanished"
|
312
|
+
else
|
313
|
+
log_replication_outcome source_db, diff
|
314
|
+
end
|
299
315
|
end
|
300
316
|
end
|
301
317
|
|
data/lib/rubyrep/session.rb
CHANGED
@@ -133,10 +133,17 @@ module RR
|
|
133
133
|
unreachable
|
134
134
|
end
|
135
135
|
|
136
|
+
# Disconnects both database connections
|
137
|
+
def disconnect_databases
|
138
|
+
[:left, :right].each do |database|
|
139
|
+
disconnect_database(database)
|
140
|
+
end
|
141
|
+
end
|
142
|
+
|
136
143
|
# Disconnnects the specified database
|
137
144
|
# * +database+: the target database (either :+left+ or :+right+)
|
138
145
|
def disconnect_database(database)
|
139
|
-
proxy, connection = @proxies[database], @
|
146
|
+
proxy, connection = @proxies[database], @connections[database]
|
140
147
|
@proxies[database] = nil
|
141
148
|
@connections[database] = nil
|
142
149
|
if proxy
|
@@ -145,15 +152,19 @@ module RR
|
|
145
152
|
end
|
146
153
|
|
147
154
|
# Refreshes both database connections
|
148
|
-
|
149
|
-
|
155
|
+
# * +options+: A options hash with the following settings
|
156
|
+
# * :+forced+: if +true+, always establish a new database connection
|
157
|
+
def refresh(options = {})
|
158
|
+
[:left, :right].each {|database| refresh_database_connection database, options}
|
150
159
|
end
|
151
160
|
|
152
161
|
# Refreshes the specified database connection.
|
153
162
|
# (I. e. reestablish if not active anymore.)
|
154
163
|
# * +database+: target database (either :+left+ or :+right+)
|
155
|
-
|
156
|
-
|
164
|
+
# * +options+: A options hash with the following settings
|
165
|
+
# * :+forced+: if +true+, always establish a new database connection
|
166
|
+
def refresh_database_connection(database, options)
|
167
|
+
if options[:forced] or database_unreachable?(database)
|
157
168
|
# step 1: disconnect both database connection (if still possible)
|
158
169
|
begin
|
159
170
|
Thread.new do
|
@@ -72,6 +72,7 @@ EOS
|
|
72
72
|
initializer = ReplicationInitializer.new session
|
73
73
|
initializer.restore_unconfigured_tables([])
|
74
74
|
initializer.drop_infrastructure
|
75
|
+
puts "Uninstall completed: rubyrep tables and triggers removed!"
|
75
76
|
end
|
76
77
|
|
77
78
|
# Entry points for executing a processing run.
|
data/lib/rubyrep/version.rb
CHANGED
data/rubyrep
ADDED
data/rubyrep.bat
ADDED
@@ -8,16 +8,16 @@ def prepare_schema
|
|
8
8
|
session = RR::Session.new
|
9
9
|
|
10
10
|
[:left, :right].each do |database|
|
11
|
+
c = session.send(database)
|
11
12
|
[:big_scan, :big_rep, :big_rep_backup].each do |table|
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
end rescue nil
|
13
|
+
c.drop_table table rescue nil
|
14
|
+
c.create_table table
|
15
|
+
c.add_column table, :diff_type, :string
|
16
|
+
(1..4).each {|i| c.add_column table, "text#{i}", :string}
|
17
|
+
c.add_column table, :text5, :text
|
18
|
+
c.add_column table, :text6, :binary
|
19
|
+
(1..3).each {|i| c.add_column table, "number#{i}", :integer}
|
20
|
+
c.add_column table, :number4, :float
|
21
21
|
end
|
22
22
|
end
|
23
23
|
end
|
@@ -202,9 +202,12 @@ describe Committers::BufferedCommitter do
|
|
202
202
|
stub_execute session
|
203
203
|
committer = Committers::BufferedCommitter.new(session)
|
204
204
|
|
205
|
-
committer.
|
206
|
-
committer.
|
207
|
-
|
205
|
+
committer.should_receive(:commit_db_transactions).twice
|
206
|
+
committer.should_receive(:begin_db_transactions).twice
|
207
|
+
committer.commit
|
208
|
+
committer.new_transaction?.should be_false
|
209
|
+
3.times {committer.commit}
|
210
|
+
committer.new_transaction?.should be_true
|
208
211
|
end
|
209
212
|
|
210
213
|
it "insert_record should commit" do
|
data/spec/committers_spec.rb
CHANGED
@@ -82,6 +82,10 @@ describe Committers::DefaultCommitter do
|
|
82
82
|
@committer.connections \
|
83
83
|
.should == {:left => @session.left, :right => @session.right}
|
84
84
|
end
|
85
|
+
|
86
|
+
it "new_transaction? should return false" do
|
87
|
+
@committer.new_transaction?.should be_false
|
88
|
+
end
|
85
89
|
|
86
90
|
it_should_behave_like "Committer"
|
87
91
|
end
|
@@ -296,6 +296,20 @@ describe ProxyConnection do
|
|
296
296
|
end
|
297
297
|
end
|
298
298
|
|
299
|
+
it "update_record should return the number of updated records" do
|
300
|
+
@connection.begin_db_transaction
|
301
|
+
begin
|
302
|
+
@connection.
|
303
|
+
update_record('scanner_records', 'id' => 1, 'name' => 'update_test').
|
304
|
+
should == 1
|
305
|
+
@connection.
|
306
|
+
update_record('scanner_records', 'id' => 0, 'name' => 'update_test').
|
307
|
+
should == 0
|
308
|
+
ensure
|
309
|
+
@connection.rollback_db_transaction
|
310
|
+
end
|
311
|
+
end
|
312
|
+
|
299
313
|
it "update_record should handle combined primary keys" do
|
300
314
|
@connection.begin_db_transaction
|
301
315
|
begin
|
@@ -377,4 +391,17 @@ describe ProxyConnection do
|
|
377
391
|
end
|
378
392
|
end
|
379
393
|
|
394
|
+
it "delete_record should return the number of deleted records" do
|
395
|
+
@connection.begin_db_transaction
|
396
|
+
begin
|
397
|
+
@connection.
|
398
|
+
delete_record('extender_combined_key', 'first_id' => 1, 'second_id' => '1').
|
399
|
+
should == 1
|
400
|
+
@connection.
|
401
|
+
delete_record('extender_combined_key', 'first_id' => 1, 'second_id' => '0').
|
402
|
+
should == 0
|
403
|
+
ensure
|
404
|
+
@connection.rollback_db_transaction
|
405
|
+
end
|
406
|
+
end
|
380
407
|
end
|
@@ -345,12 +345,14 @@ describe "ReplicationExtender", :shared => true do
|
|
345
345
|
session = nil
|
346
346
|
begin
|
347
347
|
session = Session.new
|
348
|
-
|
349
|
-
|
350
|
-
|
348
|
+
initializer = ReplicationInitializer.new(session)
|
349
|
+
initializer.silence_ddl_notices(:left) do
|
350
|
+
session.left.drop_table 'big_key_test' if session.left.tables.include? 'big_key_test'
|
351
|
+
session.left.create_table 'big_key_test'.to_sym
|
352
|
+
session.left.add_column 'big_key_test', :name, :string
|
353
|
+
session.left.remove_column 'big_key_test', 'id'
|
354
|
+
session.left.add_big_primary_key 'big_key_test', 'id'
|
351
355
|
end
|
352
|
-
session.left.add_big_primary_key 'big_key_test', 'id'
|
353
|
-
|
354
356
|
# should auto generate the primary key if not manually specified
|
355
357
|
session.left.insert_record 'big_key_test', {'name' => 'bla'}
|
356
358
|
session.left.select_one("select id from big_key_test where name = 'bla'")['id'].
|
@@ -22,6 +22,15 @@ describe ReplicationHelper do
|
|
22
22
|
helper.session.should == rep_run.session
|
23
23
|
end
|
24
24
|
|
25
|
+
it "new_transaction? should delegate to the committer" do
|
26
|
+
session = Session.new
|
27
|
+
rep_run = ReplicationRun.new(session, TaskSweeper.new(1))
|
28
|
+
helper = ReplicationHelper.new(rep_run)
|
29
|
+
c = helper.instance_eval {@committer}
|
30
|
+
c.should_receive(:new_transaction?).and_return(true)
|
31
|
+
helper.new_transaction?.should be_true
|
32
|
+
end
|
33
|
+
|
25
34
|
it "replication_run should return the current ReplicationRun instance" do
|
26
35
|
rep_run = ReplicationRun.new(Session.new, TaskSweeper.new(1))
|
27
36
|
helper = ReplicationHelper.new(rep_run)
|
@@ -437,8 +437,14 @@ describe ReplicationInitializer do
|
|
437
437
|
|
438
438
|
config.include_tables 'rr_pending_changes' # added to verify that it is ignored
|
439
439
|
|
440
|
+
# added to verify that a disabled :initial_sync is honored
|
441
|
+
config.add_table_options 'table_with_manual_key', :initial_sync => false
|
442
|
+
|
440
443
|
session = Session.new(config)
|
441
444
|
|
445
|
+
# dummy data to verify that 'table_with_manual_key' is indeed not synced
|
446
|
+
session.left.insert_record 'table_with_manual_key', :id => 1, :name => 'bla'
|
447
|
+
|
442
448
|
$stdout = StringIO.new
|
443
449
|
begin
|
444
450
|
initializer = ReplicationInitializer.new(session)
|
@@ -470,6 +476,9 @@ describe ReplicationInitializer do
|
|
470
476
|
# verify that the 'rr_pending_changes' table was not touched
|
471
477
|
initializer.trigger_exists?(:left, 'rr_pending_changes').should be_false
|
472
478
|
|
479
|
+
# verify that :initial_sync => false is honored
|
480
|
+
session.right.select_all("select * from table_with_manual_key").should be_empty
|
481
|
+
|
473
482
|
# verify that syncing is done only for unsynced tables
|
474
483
|
SyncRunner.should_not_receive(:new)
|
475
484
|
initializer.prepare_replication
|
@@ -477,6 +486,7 @@ describe ReplicationInitializer do
|
|
477
486
|
ensure
|
478
487
|
$stdout = org_stdout
|
479
488
|
if session
|
489
|
+
session.left.execute "delete from table_with_manual_key"
|
480
490
|
session.left.execute "delete from scanner_left_records_only where id = 10"
|
481
491
|
session.right.execute "delete from scanner_left_records_only"
|
482
492
|
[:left, :right].each do |database|
|
@@ -137,6 +137,76 @@ describe ReplicationRun do
|
|
137
137
|
end
|
138
138
|
end
|
139
139
|
|
140
|
+
it "run should re-raise original exception if logging to database fails" do
|
141
|
+
session = Session.new
|
142
|
+
session.left.begin_db_transaction
|
143
|
+
session.right.begin_db_transaction
|
144
|
+
begin
|
145
|
+
session.left.execute "delete from rr_pending_changes"
|
146
|
+
session.left.execute "delete from rr_logged_events"
|
147
|
+
session.left.insert_record 'rr_pending_changes', {
|
148
|
+
'change_table' => 'extender_no_record',
|
149
|
+
'change_key' => 'id|1',
|
150
|
+
'change_type' => 'D',
|
151
|
+
'change_time' => Time.now
|
152
|
+
}
|
153
|
+
run = ReplicationRun.new session, TaskSweeper.new(1)
|
154
|
+
run.replicator.stub!(:replicate_difference).and_return {raise Exception, 'dummy message'}
|
155
|
+
run.helper.stub!(:log_replication_outcome).and_return {raise Exception, 'blub'}
|
156
|
+
lambda {run.run}.should raise_error(Exception, 'dummy message')
|
157
|
+
ensure
|
158
|
+
session.left.rollback_db_transaction
|
159
|
+
session.right.rollback_db_transaction
|
160
|
+
end
|
161
|
+
end
|
162
|
+
|
163
|
+
it "run should return silently if timed out before work actually started" do
|
164
|
+
session = Session.new
|
165
|
+
session.left.begin_db_transaction
|
166
|
+
session.right.begin_db_transaction
|
167
|
+
begin
|
168
|
+
session.left.execute "delete from rr_pending_changes"
|
169
|
+
session.left.insert_record 'rr_pending_changes', {
|
170
|
+
'change_table' => 'extender_no_record',
|
171
|
+
'change_key' => 'id|1',
|
172
|
+
'change_type' => 'D',
|
173
|
+
'change_time' => Time.now
|
174
|
+
}
|
175
|
+
sweeper = TaskSweeper.new(1)
|
176
|
+
sweeper.stub!(:terminated?).and_return(true)
|
177
|
+
run = ReplicationRun.new session, sweeper
|
178
|
+
LoggedChangeLoaders.should_not_receive(:new)
|
179
|
+
run.run
|
180
|
+
ensure
|
181
|
+
session.left.rollback_db_transaction
|
182
|
+
session.right.rollback_db_transaction
|
183
|
+
end
|
184
|
+
end
|
185
|
+
|
186
|
+
it "run should rollback if timed out" do
|
187
|
+
session = Session.new
|
188
|
+
session.left.begin_db_transaction
|
189
|
+
session.right.begin_db_transaction
|
190
|
+
begin
|
191
|
+
session.left.execute "delete from rr_pending_changes"
|
192
|
+
session.left.execute "delete from rr_logged_events"
|
193
|
+
session.left.insert_record 'rr_pending_changes', {
|
194
|
+
'change_table' => 'extender_no_record',
|
195
|
+
'change_key' => 'id|1',
|
196
|
+
'change_type' => 'D',
|
197
|
+
'change_time' => Time.now
|
198
|
+
}
|
199
|
+
sweeper = TaskSweeper.new(1)
|
200
|
+
sweeper.should_receive(:terminated?).any_number_of_times.and_return(false, true)
|
201
|
+
run = ReplicationRun.new session, sweeper
|
202
|
+
run.helper.should_receive(:finalize).with(false)
|
203
|
+
run.run
|
204
|
+
ensure
|
205
|
+
session.left.rollback_db_transaction if session.left
|
206
|
+
session.right.rollback_db_transaction if session.right
|
207
|
+
end
|
208
|
+
end
|
209
|
+
|
140
210
|
it "run should not catch exceptions raised during replicator initialization" do
|
141
211
|
config = deep_copy(standard_config)
|
142
212
|
config.options[:logged_replication_events] = [:invalid_option]
|
@@ -4,6 +4,7 @@ include RR
|
|
4
4
|
|
5
5
|
describe ReplicationRunner do
|
6
6
|
before(:each) do
|
7
|
+
Initializer.configuration = standard_config
|
7
8
|
end
|
8
9
|
|
9
10
|
it "should register itself with CommandRunner" do
|
@@ -168,6 +169,36 @@ describe ReplicationRunner do
|
|
168
169
|
end
|
169
170
|
end
|
170
171
|
|
172
|
+
it "execute_once should not clean up if successful" do
|
173
|
+
runner = ReplicationRunner.new
|
174
|
+
session = Session.new
|
175
|
+
runner.instance_variable_set(:@session, session)
|
176
|
+
|
177
|
+
runner.execute_once
|
178
|
+
runner.instance_variable_get(:@session).should == session
|
179
|
+
end
|
180
|
+
|
181
|
+
it "execute_once should clean up after failed replication runs" do
|
182
|
+
runner = ReplicationRunner.new
|
183
|
+
session = Session.new
|
184
|
+
runner.instance_variable_set(:@session, session)
|
185
|
+
|
186
|
+
session.should_receive(:refresh).and_raise('bla')
|
187
|
+
lambda {runner.execute_once}.should raise_error('bla')
|
188
|
+
runner.instance_variable_get(:@session).should be_nil
|
189
|
+
end
|
190
|
+
|
191
|
+
it "execute_once should raise exception if replication run times out" do
|
192
|
+
session = Session.new
|
193
|
+
runner = ReplicationRunner.new
|
194
|
+
runner.stub!(:session).and_return(session)
|
195
|
+
terminated = mock("terminated")
|
196
|
+
terminated.stub!(:terminated?).and_return(true)
|
197
|
+
TaskSweeper.stub!(:timeout).and_return(terminated)
|
198
|
+
|
199
|
+
lambda {runner.execute_once}.should raise_error(/timed out/)
|
200
|
+
end
|
201
|
+
|
171
202
|
it "execute should start the replication" do
|
172
203
|
config = deep_copy(standard_config)
|
173
204
|
config.options[:committer] = :buffered_commit
|
data/spec/session_spec.rb
CHANGED
@@ -118,6 +118,17 @@ describe Session do # here database connection caching is _not_ disabled
|
|
118
118
|
session.right.select_one("select 1+1 as x")['x'].to_i.should == 2
|
119
119
|
end
|
120
120
|
|
121
|
+
it "disconnect_databases should disconnect both databases" do
|
122
|
+
session = Session.new(standard_config)
|
123
|
+
session.left.connection.should be_active
|
124
|
+
old_right_connection = session.right.connection
|
125
|
+
old_right_connection.should be_active
|
126
|
+
session.disconnect_databases
|
127
|
+
session.left.should be_nil
|
128
|
+
session.right.should be_nil
|
129
|
+
old_right_connection.should_not be_active
|
130
|
+
end
|
131
|
+
|
121
132
|
it "refresh should not do anyting if the connection is still active" do
|
122
133
|
session = Session.new
|
123
134
|
old_connection_id = session.right.connection.object_id
|
@@ -125,6 +136,13 @@ describe Session do # here database connection caching is _not_ disabled
|
|
125
136
|
session.right.connection.object_id.should == old_connection_id
|
126
137
|
end
|
127
138
|
|
139
|
+
it "refresh should replace active connections if forced is true" do
|
140
|
+
session = Session.new
|
141
|
+
old_connection_id = session.right.connection.object_id
|
142
|
+
session.refresh :forced => true
|
143
|
+
session.right.connection.object_id.should_not == old_connection_id
|
144
|
+
end
|
145
|
+
|
128
146
|
it "manual_primary_keys should return the specified manual primary keys" do
|
129
147
|
config = deep_copy(standard_config)
|
130
148
|
config.included_table_specs.clear
|
data/spec/spec_helper.rb
CHANGED
@@ -240,9 +240,9 @@ $start_proxy_as_external_process ||= false
|
|
240
240
|
# Starts a proxy under the given host and post
|
241
241
|
def start_proxy(host, port)
|
242
242
|
if $start_proxy_as_external_process
|
243
|
-
|
243
|
+
bin_path = File.join(File.dirname(__FILE__), "..", "bin", "rubyrep")
|
244
244
|
ruby = RUBY_PLATFORM =~ /java/ ? 'jruby' : 'ruby'
|
245
|
-
cmd = "#{ruby} #{
|
245
|
+
cmd = "#{ruby} #{bin_path} proxy -h #{host} -p #{port}"
|
246
246
|
Thread.new {system cmd}
|
247
247
|
else
|
248
248
|
url = "druby://#{host}:#{port}"
|
@@ -514,6 +514,7 @@ describe Replicators::TwoWayReplicator do
|
|
514
514
|
config.options[:replication_conflict_handling] = :left_wins
|
515
515
|
|
516
516
|
session = Session.new(config)
|
517
|
+
session.left.execute "delete from rr_logged_events"
|
517
518
|
|
518
519
|
session.left.insert_record 'rr_pending_changes', {
|
519
520
|
'change_table' => 'scanner_records',
|
@@ -593,6 +594,50 @@ describe Replicators::TwoWayReplicator do
|
|
593
594
|
end
|
594
595
|
end
|
595
596
|
|
597
|
+
it "replicate_difference should handle deletes failing due to the target record vanishing" do
|
598
|
+
begin
|
599
|
+
config = deep_copy(standard_config)
|
600
|
+
config.options[:committer] = :never_commit
|
601
|
+
config.options[:replication_conflict_handling] = :left_wins
|
602
|
+
|
603
|
+
session = Session.new(config)
|
604
|
+
|
605
|
+
session.left.insert_record 'rr_pending_changes', {
|
606
|
+
'change_table' => 'scanner_records',
|
607
|
+
'change_key' => 'id|3',
|
608
|
+
'change_new_key' => nil,
|
609
|
+
'change_type' => 'D',
|
610
|
+
'change_time' => Time.now
|
611
|
+
}
|
612
|
+
|
613
|
+
rep_run = ReplicationRun.new session, TaskSweeper.new(1)
|
614
|
+
helper = ReplicationHelper.new(rep_run)
|
615
|
+
replicator = Replicators::TwoWayReplicator.new(helper)
|
616
|
+
|
617
|
+
diff = ReplicationDifference.new LoggedChangeLoaders.new(session)
|
618
|
+
diff.load
|
619
|
+
|
620
|
+
session.right.insert_record 'rr_pending_changes', {
|
621
|
+
'change_table' => 'scanner_records',
|
622
|
+
'change_key' => 'id|3',
|
623
|
+
'change_new_key' => 'id|4',
|
624
|
+
'change_type' => 'U',
|
625
|
+
'change_time' => Time.now
|
626
|
+
}
|
627
|
+
|
628
|
+
replicator.replicate_difference diff, 2
|
629
|
+
|
630
|
+
session.right.select_one("select * from scanner_records where id = 4").
|
631
|
+
should be_nil
|
632
|
+
ensure
|
633
|
+
Committers::NeverCommitter.rollback_current_session
|
634
|
+
if session
|
635
|
+
session.left.execute "delete from rr_pending_changes"
|
636
|
+
session.left.execute "delete from rr_logged_events"
|
637
|
+
end
|
638
|
+
end
|
639
|
+
end
|
640
|
+
|
596
641
|
it "replicate_difference should handle updates failing due to the source record being deleted after the original diff was loaded" do
|
597
642
|
begin
|
598
643
|
config = deep_copy(standard_config)
|
@@ -644,4 +689,53 @@ describe Replicators::TwoWayReplicator do
|
|
644
689
|
end
|
645
690
|
end
|
646
691
|
end
|
692
|
+
|
693
|
+
it "replicate_difference should handle updates failing due to the target record being deleted after the original diff was loaded" do
|
694
|
+
begin
|
695
|
+
config = deep_copy(standard_config)
|
696
|
+
config.options[:committer] = :never_commit
|
697
|
+
config.options[:replication_conflict_handling] = :left_wins
|
698
|
+
|
699
|
+
session = Session.new(config)
|
700
|
+
|
701
|
+
session.left.insert_record 'extender_no_record', {
|
702
|
+
'id' => '2',
|
703
|
+
'name' => 'bla'
|
704
|
+
}
|
705
|
+
session.left.insert_record 'rr_pending_changes', {
|
706
|
+
'change_table' => 'extender_no_record',
|
707
|
+
'change_key' => 'id|1',
|
708
|
+
'change_new_key' => 'id|2',
|
709
|
+
'change_type' => 'U',
|
710
|
+
'change_time' => Time.now
|
711
|
+
}
|
712
|
+
|
713
|
+
rep_run = ReplicationRun.new session, TaskSweeper.new(1)
|
714
|
+
helper = ReplicationHelper.new(rep_run)
|
715
|
+
replicator = Replicators::TwoWayReplicator.new(helper)
|
716
|
+
|
717
|
+
diff = ReplicationDifference.new LoggedChangeLoaders.new(session)
|
718
|
+
diff.load
|
719
|
+
|
720
|
+
session.right.insert_record 'rr_pending_changes', {
|
721
|
+
'change_table' => 'extender_no_record',
|
722
|
+
'change_key' => 'id|1',
|
723
|
+
'change_type' => 'D',
|
724
|
+
'change_time' => Time.now
|
725
|
+
}
|
726
|
+
replicator.replicate_difference diff, 2
|
727
|
+
|
728
|
+
session.right.select_one("select * from extender_no_record").should == {
|
729
|
+
'id' => '2',
|
730
|
+
'name' => 'bla'
|
731
|
+
}
|
732
|
+
ensure
|
733
|
+
Committers::NeverCommitter.rollback_current_session
|
734
|
+
if session
|
735
|
+
session.left.execute "delete from extender_no_record"
|
736
|
+
session.right.execute "delete from extender_no_record"
|
737
|
+
session.left.execute "delete from rr_pending_changes"
|
738
|
+
end
|
739
|
+
end
|
740
|
+
end
|
647
741
|
end
|
@@ -65,22 +65,29 @@ describe UninstallRunner do
|
|
65
65
|
end
|
66
66
|
|
67
67
|
it "execute should uninstall all rubyrep elements" do
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
68
|
+
begin
|
69
|
+
org_stdout, $stdout = $stdout, StringIO.new
|
70
|
+
config = deep_copy(standard_config)
|
71
|
+
config.options[:rep_prefix] = 'rx'
|
72
|
+
session = Session.new(config)
|
73
|
+
initializer = ReplicationInitializer.new(session)
|
72
74
|
|
73
|
-
|
74
|
-
|
75
|
+
initializer.ensure_infrastructure
|
76
|
+
initializer.create_trigger :left, 'scanner_records'
|
75
77
|
|
76
|
-
|
77
|
-
|
78
|
+
runner = UninstallRunner.new
|
79
|
+
runner.stub!(:session).and_return(session)
|
80
|
+
|
81
|
+
runner.execute
|
78
82
|
|
79
|
-
|
83
|
+
initializer.trigger_exists?(:left, 'scanner_records').should be_false
|
84
|
+
initializer.change_log_exists?(:left).should be_false
|
85
|
+
session.right.tables.include?('rx_running_flags').should be_false
|
86
|
+
initializer.event_log_exists?.should be_false
|
80
87
|
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
88
|
+
$stdout.string =~ /uninstall completed/i
|
89
|
+
ensure
|
90
|
+
$stdout = org_stdout
|
91
|
+
end
|
85
92
|
end
|
86
93
|
end
|
data/tasks/java.rake
CHANGED
@@ -1,23 +1,5 @@
|
|
1
1
|
namespace :deploy do
|
2
2
|
|
3
|
-
BASH_FILE_CONTENT = <<'EOS'
|
4
|
-
#!/bin/bash
|
5
|
-
|
6
|
-
script_dir="`dirname \"$0\"`"
|
7
|
-
|
8
|
-
jruby_path="$script_dir"/jruby/bin/jruby
|
9
|
-
rubyrep_path="$script_dir"/bin/rubyrep
|
10
|
-
|
11
|
-
$jruby_path --server $rubyrep_path $*
|
12
|
-
EOS
|
13
|
-
|
14
|
-
BAT_FILE_CONTENT = <<'EOS'.gsub(/^(.*)$/,"\\1\r")
|
15
|
-
@echo off
|
16
|
-
set jruby_path=%~dp0jruby\bin\jruby.bat
|
17
|
-
set rubyrep_path=%~dp0bin\rubyrep
|
18
|
-
%jruby_path% --server %rubyrep_path% %1 %2 %3 %4 %5 %6 %7 %8 %9
|
19
|
-
EOS
|
20
|
-
|
21
3
|
desc "Create the java installation package"
|
22
4
|
task :java do
|
23
5
|
pkg_name = "rubyrep-#{RR::VERSION::STRING}"
|
@@ -28,8 +10,6 @@ EOS
|
|
28
10
|
system "mkdir -p /tmp/#{pkg_name}/jruby"
|
29
11
|
system "cp -r #{JRUBY_HOME}/* /tmp/#{pkg_name}/jruby/"
|
30
12
|
system "cd /tmp/#{pkg_name}/jruby; rm -rf samples share/ri lib/ruby/gems/1.8/doc"
|
31
|
-
File.open("/tmp/#{pkg_name}/rubyrep.bat", 'w') {|f| f.write(BAT_FILE_CONTENT)}
|
32
|
-
File.open("/tmp/#{pkg_name}/rubyrep", 'w') {|f| f.write(BASH_FILE_CONTENT)}
|
33
13
|
system "chmod a+x /tmp/#{pkg_name}/rubyrep"
|
34
14
|
system "cd /tmp; rm -f #{pkg_name}.zip; zip -r #{pkg_name}.zip #{pkg_name} >/dev/null"
|
35
15
|
system "mkdir -p pkg"
|
data.tar.gz.sig
CHANGED
Binary file
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rubyrep
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.0.
|
4
|
+
version: 1.0.8
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Arndt Lehmann
|
@@ -30,7 +30,7 @@ cert_chain:
|
|
30
30
|
NwT26VZnE2nr8g==
|
31
31
|
-----END CERTIFICATE-----
|
32
32
|
|
33
|
-
date: 2009-
|
33
|
+
date: 2009-10-01 00:00:00 +09:00
|
34
34
|
default_executable:
|
35
35
|
dependencies:
|
36
36
|
- !ruby/object:Gem::Dependency
|
@@ -144,6 +144,8 @@ files:
|
|
144
144
|
- lib/rubyrep/type_casting_cursor.rb
|
145
145
|
- lib/rubyrep/uninstall_runner.rb
|
146
146
|
- lib/rubyrep/version.rb
|
147
|
+
- rubyrep
|
148
|
+
- rubyrep.bat
|
147
149
|
- script/destroy
|
148
150
|
- script/generate
|
149
151
|
- script/txt2html
|
metadata.gz.sig
CHANGED
Binary file
|