myreplicator 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (154) hide show
  1. data/MIT-LICENSE +20 -0
  2. data/README.rdoc +3 -0
  3. data/Rakefile +40 -0
  4. data/app/assets/javascripts/myreplicator/application.js +21 -0
  5. data/app/assets/javascripts/myreplicator/chosen.jquery.min.js +10 -0
  6. data/app/assets/javascripts/myreplicator/cronwtf.js +156 -0
  7. data/app/assets/javascripts/myreplicator/exports.js +2 -0
  8. data/app/assets/javascripts/myreplicator/jquery.tipTip.minified.js +21 -0
  9. data/app/assets/stylesheets/myreplicator/FrancoisOne.ttf +0 -0
  10. data/app/assets/stylesheets/myreplicator/application.css +544 -0
  11. data/app/assets/stylesheets/myreplicator/asc-white.gif +0 -0
  12. data/app/assets/stylesheets/myreplicator/bg.gif +0 -0
  13. data/app/assets/stylesheets/myreplicator/bg.png +0 -0
  14. data/app/assets/stylesheets/myreplicator/chosen-sprite.png +0 -0
  15. data/app/assets/stylesheets/myreplicator/chosen.css +398 -0
  16. data/app/assets/stylesheets/myreplicator/clipboard-list.png +0 -0
  17. data/app/assets/stylesheets/myreplicator/cross.png +0 -0
  18. data/app/assets/stylesheets/myreplicator/desc-white.gif +0 -0
  19. data/app/assets/stylesheets/myreplicator/exports.css +4 -0
  20. data/app/assets/stylesheets/myreplicator/gear.png +0 -0
  21. data/app/assets/stylesheets/myreplicator/plus.png +0 -0
  22. data/app/assets/stylesheets/myreplicator/status-busy.png +0 -0
  23. data/app/assets/stylesheets/myreplicator/status.png +0 -0
  24. data/app/assets/stylesheets/myreplicator/tipTip.css +113 -0
  25. data/app/assets/stylesheets/myreplicator/websymbols-regular-webfont.eot +0 -0
  26. data/app/assets/stylesheets/myreplicator/websymbols-regular-webfont.svg +108 -0
  27. data/app/assets/stylesheets/myreplicator/websymbols-regular-webfont.ttf +0 -0
  28. data/app/assets/stylesheets/myreplicator/websymbols-regular-webfont.woff +0 -0
  29. data/app/assets/stylesheets/scaffold.css +56 -0
  30. data/app/controllers/myreplicator/application_controller.rb +4 -0
  31. data/app/controllers/myreplicator/exports_controller.rb +106 -0
  32. data/app/controllers/myreplicator/home_controller.rb +23 -0
  33. data/app/helpers/myreplicator/application_helper.rb +12 -0
  34. data/app/helpers/myreplicator/exports_helper.rb +4 -0
  35. data/app/models/myreplicator/export.rb +121 -0
  36. data/app/views/layouts/myreplicator/application.html.erb +24 -0
  37. data/app/views/myreplicator/exports/_form.html.erb +117 -0
  38. data/app/views/myreplicator/exports/edit.html.erb +2 -0
  39. data/app/views/myreplicator/exports/index.html.erb +56 -0
  40. data/app/views/myreplicator/exports/new.html.erb +2 -0
  41. data/app/views/myreplicator/exports/show.html.erb +28 -0
  42. data/app/views/myreplicator/home/_home_menu.erb +5 -0
  43. data/app/views/myreplicator/home/errors.html.erb +10 -0
  44. data/app/views/myreplicator/home/index.html.erb +58 -0
  45. data/config/routes.rb +6 -0
  46. data/db/migrate/20121025191622_create_myreplicator_exports.rb +35 -0
  47. data/lib/configuration.rb +25 -0
  48. data/lib/exporter/export_metadata.rb +198 -0
  49. data/lib/exporter/export_metadata.rb~ +9 -0
  50. data/lib/exporter/mysql_exporter.rb +187 -0
  51. data/lib/exporter/sql_commands.rb +126 -0
  52. data/lib/exporter/sql_commands.rb~ +5 -0
  53. data/lib/exporter.rb +3 -0
  54. data/lib/loader/import_sql.rb +91 -0
  55. data/lib/loader/import_sql.rb~ +27 -0
  56. data/lib/loader/loader.rb +122 -0
  57. data/lib/loader/loader.rb~ +4 -0
  58. data/lib/myreplicator/engine.rb +5 -0
  59. data/lib/myreplicator/version.rb +3 -0
  60. data/lib/myreplicator.rb +34 -0
  61. data/lib/tasks/myreplicator_tasks.rake +4 -0
  62. data/lib/transporter/parallelizer.rb +78 -0
  63. data/lib/transporter/transporter.rb +80 -0
  64. data/test/dummy/README.rdoc +261 -0
  65. data/test/dummy/Rakefile +7 -0
  66. data/test/dummy/app/assets/javascripts/application.js +15 -0
  67. data/test/dummy/app/assets/stylesheets/application.css +13 -0
  68. data/test/dummy/app/controllers/application_controller.rb +3 -0
  69. data/test/dummy/app/helpers/application_helper.rb +2 -0
  70. data/test/dummy/app/views/layouts/application.html.erb +14 -0
  71. data/test/dummy/config/application.rb +59 -0
  72. data/test/dummy/config/boot.rb +10 -0
  73. data/test/dummy/config/database.yml +42 -0
  74. data/test/dummy/config/database.yml.sample +47 -0
  75. data/test/dummy/config/database.yml.sample~ +26 -0
  76. data/test/dummy/config/database.yml~ +35 -0
  77. data/test/dummy/config/environment.rb +5 -0
  78. data/test/dummy/config/environments/development.rb +37 -0
  79. data/test/dummy/config/environments/production.rb +67 -0
  80. data/test/dummy/config/environments/test.rb +37 -0
  81. data/test/dummy/config/initializers/backtrace_silencers.rb +7 -0
  82. data/test/dummy/config/initializers/inflections.rb +15 -0
  83. data/test/dummy/config/initializers/mime_types.rb +5 -0
  84. data/test/dummy/config/initializers/secret_token.rb +7 -0
  85. data/test/dummy/config/initializers/session_store.rb +8 -0
  86. data/test/dummy/config/initializers/wrap_parameters.rb +14 -0
  87. data/test/dummy/config/locales/en.yml +5 -0
  88. data/test/dummy/config/myreplicator.yml +22 -0
  89. data/test/dummy/config/myreplicator.yml.sample +23 -0
  90. data/test/dummy/config/myreplicator.yml~ +21 -0
  91. data/test/dummy/config/routes.rb +4 -0
  92. data/test/dummy/config.ru +4 -0
  93. data/test/dummy/db/migrate/20121101005152_sample_data.rb +24 -0
  94. data/test/dummy/db/migrate/20121115194022_create_myreplicator_exports.myreplicator.rb +36 -0
  95. data/test/dummy/db/schema.rb +45 -0
  96. data/test/dummy/db/seeds.rb +13 -0
  97. data/test/dummy/db/seeds.rb~ +1 -0
  98. data/test/dummy/log/development.log +1364 -0
  99. data/test/dummy/log/test.log +49 -0
  100. data/test/dummy/public/404.html +26 -0
  101. data/test/dummy/public/422.html +26 -0
  102. data/test/dummy/public/500.html +25 -0
  103. data/test/dummy/public/favicon.ico +0 -0
  104. data/test/dummy/script/rails +6 -0
  105. data/test/dummy/test/fixtures/myreplicator_exports.yml +0 -0
  106. data/test/dummy/tmp/cache/assets/C2E/D00/sprockets%2F667019818351638709494c01bddb5f68 +0 -0
  107. data/test/dummy/tmp/cache/assets/C83/BA0/sprockets%2F701a6339a558e5af28f150c161f43878 +0 -0
  108. data/test/dummy/tmp/cache/assets/C8B/150/sprockets%2F37163d05e55ad0b31b602ac5330412e3 +0 -0
  109. data/test/dummy/tmp/cache/assets/CBF/800/sprockets%2F00142a873933017aaa760316d0e2dcea +0 -0
  110. data/test/dummy/tmp/cache/assets/CC5/870/sprockets%2F4e91734f6f02a779d39f8272f627dd24 +0 -0
  111. data/test/dummy/tmp/cache/assets/CC9/1C0/sprockets%2Fa7a2b5a56180e1b21f783a9b30c03167 +0 -0
  112. data/test/dummy/tmp/cache/assets/CD5/B90/sprockets%2Fc999d13a6a21113981c0d820e8043bdf +0 -0
  113. data/test/dummy/tmp/cache/assets/CD7/030/sprockets%2F9ba4859590582b8b72a650b2b00b6cd2 +0 -0
  114. data/test/dummy/tmp/cache/assets/CDE/780/sprockets%2F6982ce9303b4e69c26f2a1a246a180e7 +0 -0
  115. data/test/dummy/tmp/cache/assets/CE5/670/sprockets%2Fe9e4122f1706626a21da6f8457f088ce +0 -0
  116. data/test/dummy/tmp/cache/assets/CF7/820/sprockets%2F6284656df87a7eb2545ed9b957560a7b +0 -0
  117. data/test/dummy/tmp/cache/assets/D00/9B0/sprockets%2F2bc203eb4802b393a589093debb65c04 +0 -0
  118. data/test/dummy/tmp/cache/assets/D00/A90/sprockets%2F3fa6fcf2205c530208681446cbc36bd3 +0 -0
  119. data/test/dummy/tmp/cache/assets/D0B/B30/sprockets%2F55059589d999952597c5c86e5becaf4e +0 -0
  120. data/test/dummy/tmp/cache/assets/D0D/DA0/sprockets%2F34d6b075a16a5a58ff4050988d8bd4b0 +0 -0
  121. data/test/dummy/tmp/cache/assets/D12/B40/sprockets%2F9c825562fe2a2a38bd6f41a635265bd9 +0 -0
  122. data/test/dummy/tmp/cache/assets/D1B/D40/sprockets%2F7cc2142509e95f7168a82a652d8d9dea +0 -0
  123. data/test/dummy/tmp/cache/assets/D1D/700/sprockets%2Ffe9cb975216709e2881c74b3d1d3e35f +0 -0
  124. data/test/dummy/tmp/cache/assets/D20/A20/sprockets%2Fb503e93ff1966dd94d03e79f291d75c1 +0 -0
  125. data/test/dummy/tmp/cache/assets/D26/A70/sprockets%2F63d95ae156df465783cd78e95069b2cc +0 -0
  126. data/test/dummy/tmp/cache/assets/D2B/E60/sprockets%2F8615ecf645b553c959544af9ff8438da +0 -0
  127. data/test/dummy/tmp/cache/assets/D34/F70/sprockets%2Fb93de9992473bee94e369fe3198c529c +0 -0
  128. data/test/dummy/tmp/cache/assets/D36/4D0/sprockets%2Fc050a64b5a803a638e155d05dcfe577d +0 -0
  129. data/test/dummy/tmp/cache/assets/D3E/310/sprockets%2F333a2a7535eac766267ebb7d5c2ab489 +0 -0
  130. data/test/dummy/tmp/cache/assets/D3F/A00/sprockets%2F7a803404e1f60b8d672d763cb9ba8af5 +0 -0
  131. data/test/dummy/tmp/cache/assets/D50/570/sprockets%2F6c1d20a178f66e798958d1e437fdb5da +0 -0
  132. data/test/dummy/tmp/cache/assets/D57/420/sprockets%2F937ea7429c536578ec7b688dee0cdf41 +0 -0
  133. data/test/dummy/tmp/cache/assets/D69/6F0/sprockets%2F94fff7f55bc4c300b25f3f9361ac1a52 +0 -0
  134. data/test/dummy/tmp/cache/assets/D86/D00/sprockets%2Fa4f32b4234d0d1bba272cd75e0d48e1d +0 -0
  135. data/test/dummy/tmp/cache/assets/D8B/B60/sprockets%2Faa32227c440a378ccd21218eefeb80bf +0 -0
  136. data/test/dummy/tmp/cache/assets/D9F/0B0/sprockets%2Faf0d2e69be3a6b56a76c20bf14d9e468 +0 -0
  137. data/test/dummy/tmp/cache/assets/DA8/910/sprockets%2Fab5775c4a837bd4d97ac394d473cda9b +0 -0
  138. data/test/dummy/tmp/cache/assets/DC0/100/sprockets%2F7a5d4f0d352bceed0dce0449c82251bd +0 -0
  139. data/test/dummy/tmp/cache/assets/DD2/490/sprockets%2Fa452ee92a092bc2feabc572cce49896d +0 -0
  140. data/test/dummy/tmp/cache/assets/DE1/320/sprockets%2F9f44ecdec8ceeef70871e15d88a448b1 +0 -0
  141. data/test/dummy/tmp/cache/assets/DF8/5D0/sprockets%2Fb815ed34d61cfed96222daa3bfd1d84d +0 -0
  142. data/test/dummy/tmp/cache/assets/E16/C70/sprockets%2F21ad93418ff75ceac86c7a85dfffe8f6 +0 -0
  143. data/test/dummy/tmp/cache/assets/E35/4F0/sprockets%2F96b1cdf8db6a1c8eb8abcce05958ae74 +0 -0
  144. data/test/dummy/tmp/cache/assets/E4E/300/sprockets%2Fefaae6e1a19a7c8f3acebdd5a36a6103 +0 -0
  145. data/test/fixtures/myreplicator/exports.yml +11 -0
  146. data/test/functional/myreplicator/exports_controller_test.rb +51 -0
  147. data/test/integration/navigation_test.rb +10 -0
  148. data/test/myreplicator_test.rb +7 -0
  149. data/test/test_helper.rb +15 -0
  150. data/test/unit/helpers/myreplicator/exports_helper_test.rb +6 -0
  151. data/test/unit/myreplicator/export_test.rb +10 -0
  152. data/test/unit/myreplicator/exporter_test.rb +11 -0
  153. data/test/unit/myreplicator/exporter_test.rb~ +10 -0
  154. metadata +410 -0
@@ -0,0 +1,126 @@
1
+ module Myreplicator
2
+ module SqlCommands
3
+
4
+ def self.mysqldump *args
5
+ options = args.extract_options!
6
+ options.reverse_merge! :flags => []
7
+ db = options[:db]
8
+
9
+ flags = ""
10
+
11
+ self.dump_flags.each_pair do |flag, value|
12
+ if options[:flags].include? flag
13
+ flags += " --#{flag} "
14
+ elsif value
15
+ flags += " --#{flag} "
16
+ end
17
+ end
18
+
19
+ # Database host when ssh'ed into the db server
20
+ db_host = ssh_configs(db)["ssh_db_host"].nil? ? "127.0.0.1" : ssh_configs(db)["ssh_db_host"]
21
+
22
+ cmd = Myreplicator.mysqldump
23
+ cmd += "#{flags} -u#{db_configs(db)["username"]} -p#{db_configs(db)["password"]} "
24
+ cmd += "-h#{db_host} " if db_configs(db)["host"]
25
+ cmd += " -P#{db_configs(db)["port"]} " if db_configs(db)["port"]
26
+ cmd += " #{db} "
27
+ cmd += " #{options[:table_name]} "
28
+ cmd += "--result-file=#{options[:filepath]} "
29
+
30
+ # cmd += "--tab=#{options[:filepath]} "
31
+ # cmd += "--fields-enclosed-by=\'\"\' "
32
+ # cmd += "--fields-escaped-by=\'\\\\\' "
33
+
34
+ return cmd
35
+ end
36
+
37
+ def self.db_configs db
38
+ ActiveRecord::Base.configurations[db]
39
+ end
40
+
41
+ def self.ssh_configs db
42
+ Myreplicator.configs[db]
43
+ end
44
+
45
+ def self.dump_flags
46
+ {"add-locks" => true,
47
+ "compact" => false,
48
+ "lock-tables" => false,
49
+ "no-create-db" => true,
50
+ "no-data" => false,
51
+ "quick" => true,
52
+ "skip-add-drop-table" => false,
53
+ "create-options" => false,
54
+ "single-transaction" => false
55
+ }
56
+ end
57
+
58
+ def self.mysql_export *args
59
+ options = args.extract_options!
60
+ options.reverse_merge! :flags => []
61
+ db = options[:db]
62
+ # Database host when ssh'ed into the db server
63
+ db_host = ssh_configs(db)["ssh_db_host"].nil? ? "127.0.0.1" : ssh_configs(db)["ssh_db_host"]
64
+
65
+ flags = ""
66
+
67
+ self.mysql_flags.each_pair do |flag, value|
68
+ if options[:flags].include? flag
69
+ flags += " --#{flag} "
70
+ elsif value
71
+ flags += " --#{flag} "
72
+ end
73
+ end
74
+
75
+ cmd = Myreplicator.mysql
76
+ cmd += "#{flags} -u#{db_configs(db)["username"]} -p#{db_configs(db)["password"]} "
77
+ cmd += "-h#{db_host} " if db_configs(db)["host"].blank?
78
+ cmd += db_configs(db)["port"].blank? ? "-P3306 " : "-P#{db_configs(db)["port"]} "
79
+ cmd += "--execute=\"#{options[:sql]}\" "
80
+ cmd += " > #{options[:filepath]} "
81
+
82
+ puts cmd
83
+ return cmd
84
+ end
85
+
86
+ def self.mysql_flags
87
+ {"column-names" => false,
88
+ "quick" => true,
89
+ "reconnect" => true
90
+ }
91
+ end
92
+
93
+ def self.export_sql *args
94
+ options = args.extract_options!
95
+ sql = "SELECT * FROM #{options[:db]}.#{options[:table]} "
96
+
97
+ if options[:incremental_col] && options[:incremental_val]
98
+ if options[:incremental_col_type] == "datetime"
99
+ sql += "WHERE #{options[:incremental_col]} >= '#{options[:incremental_val]}'"
100
+ else
101
+ sql += "WHERE #{options[:incremental_col]} >= #{options[:incremental_val]}"
102
+ end
103
+ end
104
+
105
+ return sql
106
+ end
107
+
108
+ def self.max_value_sql *args
109
+ options = args.extract_options!
110
+ sql = ""
111
+
112
+ if options[:incremental_col]
113
+ sql = "SELECT max(#{options[:incremental_col]}) FROM #{options[:db]}.#{options[:table]}"
114
+ else
115
+ raise Myreplicator::Exceptions::MissingArgs.new("Missing Incremental Column Parameter")
116
+ end
117
+
118
+ return sql
119
+ end
120
+
121
+ def self.mysql_export_outfile
122
+
123
+ end
124
+
125
+ end
126
+ end
@@ -0,0 +1,5 @@
1
+ module Myreplicator
2
+ module SqlComands
3
+
4
+ end
5
+ end
data/lib/exporter.rb ADDED
@@ -0,0 +1,3 @@
1
+ Dir["#{File.expand_path(File.dirname(__FILE__))}/exporter/*.rb"].each { | f | require File.expand_path(f) }
2
+ Dir["#{File.expand_path(File.dirname(__FILE__))}/transporter/*.rb"].each { | f | require File.expand_path(f) }
3
+ Dir["#{File.expand_path(File.dirname(__FILE__))}/loader/*.rb"].each { | f | require File.expand_path(f) }
@@ -0,0 +1,91 @@
1
+ module Myreplicator
2
+ class ImportSql
3
+ class << self
4
+
5
+ def load_data_infile *args
6
+ options = args.extract_options!
7
+ sql = build_load_data_infile options
8
+
9
+ cmd = mysql_cmd(options[:db])
10
+ cmd += " --local_infile=1 " # Used for mysql versions that do not support -e and LDI
11
+ cmd += "-e \"#{sql}\" "
12
+
13
+ return cmd
14
+ end
15
+
16
+ def build_load_data_infile options
17
+ options.reverse_merge!(:replace => true,
18
+ :fields_terminated_by => "\\t",
19
+ :lines_terminated_by => "\\n"
20
+ )
21
+
22
+
23
+ handle = options[:replace] ? 'REPLACE' : 'IGNORE'
24
+
25
+ sql = "LOAD DATA LOCAL INFILE '#{options[:filepath]}' #{handle} "
26
+ sql += "INTO TABLE #{options[:db]}.#{options[:table_name]} "
27
+
28
+ if options.include?(:character_set)
29
+ sql << " CHARACTER SET #{options[:character_set]}"
30
+ end
31
+
32
+ if options.include?(:fields_terminated_by) or options.include?(:enclosed_by) or options.include?(:escaped_by)
33
+ sql << " FIELDS"
34
+ end
35
+ if options.include?(:fields_terminated_by)
36
+ sql << " TERMINATED BY '#{options[:fields_terminated_by]}'"
37
+ end
38
+ if options.include?(:enclosed_by)
39
+ sql << " ENCLOSED BY '#{options[:enclosed_by]}'"
40
+ end
41
+ if options.include?(:escaped_by)
42
+ sql << " ESCAPED BY '#{options[:escaped_by]}'"
43
+ end
44
+
45
+ if options.include?(:starting_by) or options.include?(:lines_terminated_by)
46
+ sql << " LINES"
47
+ end
48
+ if options.include?(:starting_by)
49
+ sql << " STARTING BY '#{options[:starting_by]}'"
50
+ end
51
+ if options.include?(:lines_terminated_by)
52
+ sql << " TERMINATED BY '#{options[:lines_terminated_by]}'"
53
+ end
54
+
55
+ if options.include?(:ignore)
56
+ sql << " IGNORE #{options[:ignore]} LINES"
57
+ end
58
+
59
+ if options.include?(:fields) and !options[:fields].empty?
60
+ sql << "( #{options[:fields].join(', ')} )"
61
+ end
62
+
63
+ return sql
64
+ end
65
+
66
+ def initial_load *args
67
+ options = args.extract_options!
68
+
69
+ cmd = mysql_cmd(options[:db])
70
+ cmd += " #{options[:db]} "
71
+ cmd += " < #{options[:filepath]} "
72
+
73
+ return cmd
74
+ end
75
+
76
+ def mysql_cmd db
77
+ # Destination database host
78
+ db_host = SqlCommands.db_configs(db).has_key?("host") ? SqlCommands.db_configs(db)["host"] : "127.0.0.1"
79
+
80
+ cmd = Myreplicator.mysql
81
+ cmd += " -u#{SqlCommands.db_configs(db)["username"]} -p#{SqlCommands.db_configs(db)["password"]} "
82
+ cmd += " -h#{db_host} "
83
+ cmd += " -P#{SqlCommands.db_configs(db)["port"]} " if SqlCommands.db_configs(db)["port"]
84
+
85
+ return cmd
86
+ end
87
+
88
+ end #self
89
+
90
+ end
91
+ end
@@ -0,0 +1,27 @@
1
+ module Myreplicator
2
+ module ImportSql
3
+
4
+ def self.load_data_infile *args
5
+ options = args.extract_options!
6
+ sql = ""
7
+ end
8
+
9
+ def self.initial_load *args
10
+ options = args.extract_options!
11
+ db = options[:db]
12
+ cmd = ""
13
+
14
+ # Destination database host
15
+ db_host = db_configs(db).has_key?("host") ? db_configs(db)["host"] : "127.0.0.1"
16
+
17
+ cmd = Myreplicator.mysql
18
+ cmd += "-u#{db_configs(db)["username"]} -p#{db_configs(db)["password"]} "
19
+ cmd += "-h#{db_host} "
20
+ cmd += " -P#{db_configs(db)["port"]} " if db_configs(db)["port"]
21
+ cmd += " #{db} "
22
+ cmd += " #{options[:table_name]} "
23
+ cmd += " < #{options[:filepath]} "
24
+ end
25
+
26
+ end
27
+ end
@@ -0,0 +1,122 @@
1
+ require "exporter"
2
+
3
+ module Myreplicator
4
+ class Loader
5
+
6
+ def initialize *args
7
+ options = args.extract_options!
8
+ end
9
+
10
+ def tmp_dir
11
+ @tmp_dir ||= File.join(Myreplicator.app_root,"tmp", "myreplicator")
12
+ end
13
+
14
+ def load
15
+ initials = []
16
+ incrementals = []
17
+
18
+ metadata_files.each do |metadata|
19
+ if metadata.export_type == "initial"
20
+ initials << metadata
21
+ else
22
+ incrementals << metadata
23
+ end
24
+ end
25
+
26
+ initials.each do |metadata|
27
+ puts metadata.table
28
+ initial_load metadata
29
+ cleanup metadata
30
+ end
31
+
32
+ incrementals.each do |metadata|
33
+ puts metadata.table
34
+ incremental_load metadata
35
+ cleanup metadata
36
+ end
37
+ end
38
+
39
+ ##
40
+ # Creates table and loads data
41
+ ##
42
+ def initial_load metadata
43
+ exp = Export.find(metadata.export_id)
44
+ unzip(metadata.filename)
45
+ metadata.zipped = false
46
+
47
+ cmd = ImportSql.initial_load(:db => exp.destination_schema,
48
+ :filepath => metadata.destination_filepath(tmp_dir))
49
+ puts cmd
50
+ result = `#{cmd}` # execute
51
+ unless result.nil?
52
+ if result.size > 0
53
+ raise Exceptions::LoaderError.new("Initial Load #{metadata.filename} Failed!\n#{result}")
54
+ end
55
+ end
56
+ end
57
+
58
+ ##
59
+ # Loads data incrementally
60
+ # Uses the values specified in the metadatta object
61
+ ##
62
+ def incremental_load metadata
63
+ exp = Export.find(metadata.export_id)
64
+ unzip(metadata.filename)
65
+ metadata.zipped = false
66
+
67
+ cmd = ImportSql.load_data_infile(:table_name => exp.table_name,
68
+ :db => exp.destination_schema,
69
+ :filepath => metadata.destination_filepath(tmp_dir))
70
+ puts cmd
71
+ result = `#{cmd}` # execute
72
+ unless result.nil?
73
+ if result.size > 0
74
+ raise Exceptions::LoaderError.new("Incremental Load #{metadata.filename} Failed!\n#{result}")
75
+ end
76
+ end
77
+ end
78
+
79
+ ##
80
+ # Deletes the metadata file and extract
81
+ ##
82
+ def cleanup metadata
83
+ puts "Cleaning up..."
84
+ FileUtils.rm "#{metadata.destination_filepath(tmp_dir)}.json" # json file
85
+ FileUtils.rm metadata.destination_filepath(tmp_dir) # dump file
86
+ end
87
+
88
+ ##
89
+ # Unzips file
90
+ # Checks if the file exists or already unzipped
91
+ ##
92
+ def unzip filename
93
+ cmd = "cd #{tmp_dir}; gunzip #{filename}"
94
+ passed = false
95
+ if File.exist?(File.join(tmp_dir,filename))
96
+ result = `#{cmd}`
97
+ unless result.nil?
98
+ puts result
99
+ unless result.length > 0
100
+ passed = true
101
+ end
102
+ else
103
+ passed = true
104
+ end
105
+ elsif File.exist?(File.join(tmp_dir,filename.gsub(".gz","")))
106
+ puts "File already unzipped"
107
+ passed = true
108
+ end
109
+
110
+ raise Exceptions::LoaderError.new("Unzipping #{filename} Failed!") unless passed
111
+ end
112
+
113
+ def metadata_files
114
+ files = []
115
+ Dir.glob(File.join(tmp_dir, "*.json")).each do |json_file|
116
+ files << ExportMetadata.new(:metadata_path => json_file)
117
+ end
118
+ return files
119
+ end
120
+
121
+ end
122
+ end
@@ -0,0 +1,4 @@
1
+ module Myreplicator
2
+ class Transporter
3
+ end
4
+ end
@@ -0,0 +1,5 @@
1
+ module Myreplicator
2
+ class Engine < ::Rails::Engine
3
+ isolate_namespace Myreplicator
4
+ end
5
+ end
@@ -0,0 +1,3 @@
1
+ module Myreplicator
2
+ VERSION = "0.0.1"
3
+ end
@@ -0,0 +1,34 @@
1
+ require "myreplicator/engine"
2
+
3
+
4
+ module Myreplicator
5
+ mattr_accessor :app_root, :tmp_path, :mysql, :mysqldump, :configs
6
+
7
+ class Engine < Rails::Engine
8
+
9
+ initializer "myreplicator.configure_rails_initialization" do |app|
10
+ Myreplicator.app_root = app.root #assigning app root as rails.root is not accessible
11
+ yml = YAML.load(File.read("#{Myreplicator.app_root}/config/myreplicator.yml"))
12
+
13
+ Myreplicator.mysql = yml["myreplicator"]["mysql"]
14
+ Myreplicator.mysqldump = yml["myreplicator"]["mysqldump"]
15
+
16
+ if yml["myreplicator"]["tmp_path"].blank?
17
+ Myreplicator.tmp_path = File.join(Myreplicator.app_root, "tmp", "myreplicator")
18
+ else
19
+ Myreplicator.tmp_path = yml["myreplicator"]["tmp_path"]
20
+ end
21
+
22
+ Myreplicator.configs = yml
23
+ end
24
+
25
+ end
26
+
27
+ module Exceptions
28
+ class MissingArgs < StandardError; end
29
+ class ExportError < StandardError; end
30
+ class LoaderError < StandardError; end
31
+ class ExportIgnored < StandardError; end
32
+ end
33
+
34
+ end
@@ -0,0 +1,4 @@
1
+ # desc "Explaining what the task does"
2
+ # task :myreplicator do
3
+ # # Task goes here
4
+ # end
@@ -0,0 +1,78 @@
1
+ require "thread"
2
+
3
+ module Myreplicator
4
+ class Parallelizer
5
+
6
+ attr_accessor :queue
7
+
8
+ def initialize *args
9
+ options = args.extract_options!
10
+ @queue = Queue.new
11
+ @threads = []
12
+ @max_threads = options[:max_threads].nil? ? 10 : options[:max_threads]
13
+ end
14
+
15
+ ##
16
+ # Runs while there are jobs in the queue
17
+ # Waits for a second and checks for available threads
18
+ # Exits when all jobs are allocated in threads
19
+ ##
20
+ def run
21
+ @done = false
22
+ @manager_running = false
23
+
24
+ while @queue.size > 0
25
+ if @threads.size <= @max_threads
26
+ @threads << Thread.new(@queue.pop) do |proc|
27
+ Thread.current[:status] = 'running' # Manually Set Thread state for Checks
28
+ Transporter.new.instance_exec(proc[:params], &proc[:block])
29
+ Thread.current[:status] = 'done'
30
+ end
31
+ else
32
+ unless @manager_running
33
+ manage_threads
34
+ @manager_running = true
35
+ end
36
+ sleep 1
37
+ end
38
+ end
39
+
40
+ manage_threads unless @manager_running
41
+
42
+ # Waits until all threads are completed
43
+ # Before exiting
44
+ while !@done
45
+ sleep 1
46
+ end
47
+
48
+ end
49
+
50
+ ##
51
+ # Clears dead threads,
52
+ # frees thread pool for more jobs
53
+ # Exits when no more threads are left
54
+ ##
55
+ def manage_threads
56
+ Thread.new do
57
+ while(@threads.size > 0)
58
+ done = []
59
+ @threads.each do |t|
60
+ done << t if t[:status] == "done"
61
+ end
62
+
63
+ done.each{|d| @threads.delete(d)} # Clear dead threads
64
+
65
+ # If no more jobs are left, mark done
66
+
67
+ if @queue.size == 0 && @threads.size == 0
68
+ @done = true
69
+ else
70
+ sleep 2 # Wait for more threads to spawn
71
+ end
72
+
73
+ end
74
+ end
75
+ end
76
+
77
+ end
78
+ end
@@ -0,0 +1,80 @@
1
+ require "exporter"
2
+
3
+ module Myreplicator
4
+ class Transporter
5
+
6
+ def initialize *args
7
+ options = args.extract_options!
8
+ end
9
+
10
+ def tmp_dir
11
+ @tmp_dir ||= File.join(Myreplicator.app_root,"tmp", "myreplicator")
12
+ Dir.mkdir(@tmp_dir) unless File.directory?(@tmp_dir)
13
+ @tmp_dir
14
+ end
15
+
16
+ def transfer
17
+ unique_jobs = Export.where("state != 'failed' and active = 1").group("source_schema")
18
+
19
+ unique_jobs.each do |export|
20
+ download export
21
+ end
22
+ end
23
+
24
+ def download export
25
+ ssh = export.ssh_to_source
26
+ parallel_download(export, ssh, completed_files(ssh, export))
27
+ end
28
+
29
+ def parallel_download export, ssh, files
30
+ p = Parallelizer.new
31
+
32
+ files.each do |filename|
33
+ puts filename
34
+ p.queue << {:params =>[ssh, export, filename], :block => download_file}
35
+ end
36
+
37
+ p.run
38
+ end
39
+
40
+ def download_file
41
+ proc = Proc.new { |params|
42
+ ssh = params[0]
43
+ export = params[1]
44
+ filename = params[2]
45
+ sftp = export.sftp_to_source
46
+ json_file = remote_path(export, filename)
47
+ json_local_path = File.join(tmp_dir,filename)
48
+ puts "Downloading #{json_file}"
49
+ sftp.download!(json_file, json_local_path)
50
+ dump_file = get_dump_path(json_local_path)
51
+ puts "Downloading #{dump_file}"
52
+ sftp.download!(dump_file, File.join(tmp_dir, dump_file.split("/").last))
53
+ }
54
+ end
55
+
56
+ def completed_files ssh, export
57
+ done_files = ssh.exec!(get_done_files(export))
58
+
59
+ unless done_files.blank?
60
+ return done_files.split("\n")
61
+ end
62
+
63
+ return []
64
+ end
65
+
66
+ def get_dump_path json_path
67
+ metadata = ExportMetadata.new(:metadata_path => json_path)
68
+ return metadata.export_path
69
+ end
70
+
71
+ def remote_path export, filename
72
+ File.join(Myreplicator.configs[export.source_schema]["ssh_tmp_dir"], filename)
73
+ end
74
+
75
+ def get_done_files export
76
+ cmd = "cd #{Myreplicator.configs[export.source_schema]["ssh_tmp_dir"]}; grep -l export_completed *.json"
77
+ end
78
+
79
+ end
80
+ end