rubyrep 1.0.7 → 1.0.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|