backup 2.1.2 → 2.2.0
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/CHANGELOG +41 -0
- data/README.textile +226 -0
- data/Rakefile +9 -9
- data/VERSION +1 -1
- data/backup.gemspec +21 -9
- data/generators/backup/templates/config/backup.rb +102 -12
- data/generators/backup/templates/tasks/backup.rake +16 -7
- data/lib/backup.rb +24 -6
- data/lib/backup/adapters/archive.rb +22 -10
- data/lib/backup/adapters/base.rb +15 -3
- data/lib/backup/adapters/custom.rb +74 -0
- data/lib/backup/adapters/mysql.rb +51 -11
- data/lib/backup/adapters/postgresql.rb +88 -0
- data/lib/backup/configuration/adapter.rb +12 -1
- data/lib/backup/configuration/adapter_options.rb +19 -0
- data/lib/backup/configuration/helpers.rb +5 -0
- data/lib/backup/record/ftp.rb +94 -0
- data/lib/backup/record/s3.rb +0 -2
- data/lib/backup/record/sftp.rb +92 -0
- data/lib/backup/storage/ftp.rb +34 -0
- data/lib/backup/storage/s3.rb +1 -1
- data/lib/backup/storage/scp.rb +1 -1
- data/lib/backup/storage/sftp.rb +28 -0
- metadata +24 -6
- data/README.rdoc +0 -222
@@ -9,8 +9,10 @@ namespace :backup do
|
|
9
9
|
task :truncate => :environment do
|
10
10
|
backup = Backup::Setup.new(ENV['trigger'], @backup_procedures)
|
11
11
|
case backup.procedure.storage_name.to_sym
|
12
|
-
when :s3
|
13
|
-
when :scp
|
12
|
+
when :s3 then Backup::Record::S3.destroy_all :trigger => ENV['trigger'], :storage => 's3'
|
13
|
+
when :scp then Backup::Record::SCP.destroy_all :trigger => ENV['trigger'], :storage => 'scp'
|
14
|
+
when :ftp then Backup::Record::FTP.destroy_all :trigger => ENV['trigger'], :storage => 'ftp'
|
15
|
+
when :sftp then Backup::Record::SFTP.destroy_all :trigger => ENV['trigger'], :storage => 'sftp'
|
14
16
|
end
|
15
17
|
end
|
16
18
|
|
@@ -18,23 +20,30 @@ namespace :backup do
|
|
18
20
|
task :truncate_all => :environment do
|
19
21
|
Backup::Record::S3.destroy_all
|
20
22
|
Backup::Record::SCP.destroy_all
|
23
|
+
Backup::Record::FTP.destroy_all
|
24
|
+
Backup::Record::SFTP.destroy_all
|
21
25
|
end
|
22
26
|
|
23
27
|
desc "Destroys all records for the specified \"trigger\", including the physical files on s3 or the remote server."
|
24
28
|
task :destroy => :environment do
|
25
29
|
backup = Backup::Setup.new(ENV['trigger'], @backup_procedures)
|
26
30
|
case backup.procedure.storage_name.to_sym
|
27
|
-
when :s3
|
28
|
-
when :scp
|
31
|
+
when :s3 then Backup::Record::S3.destroy_all_backups backup.procedure, ENV['trigger']
|
32
|
+
when :scp then Backup::Record::SCP.destroy_all_backups backup.procedure, ENV['trigger']
|
33
|
+
when :ftp then Backup::Record::FTP.destroy_all_backups backup.procedure, ENV['trigger']
|
34
|
+
when :sftp then Backup::Record::SFTP.destroy_all_backups backup.procedure, ENV['trigger']
|
29
35
|
end
|
30
36
|
end
|
31
37
|
|
32
38
|
desc "Destroys all records for the specified \"trigger\", including the physical files on s3 or the remote server."
|
33
39
|
task :destroy_all => :environment do
|
34
|
-
@backup_procedures
|
40
|
+
backup = Backup::Setup.new(false, @backup_procedures)
|
41
|
+
backup.procedures.each do |backup_procedure|
|
35
42
|
case backup_procedure.storage_name.to_sym
|
36
|
-
when :s3
|
37
|
-
when :scp
|
43
|
+
when :s3 then Backup::Record::S3.destroy_all_backups backup_procedure, backup_procedure.trigger
|
44
|
+
when :scp then Backup::Record::SCP.destroy_all_backups backup_procedure, backup_procedure.trigger
|
45
|
+
when :ftp then Backup::Record::FTP.destroy_all_backups backup_procedure, backup_procedure.trigger
|
46
|
+
when :sftp then Backup::Record::SFTP.destroy_all_backups backup_procedure, backup_procedure.trigger
|
38
47
|
end
|
39
48
|
end
|
40
49
|
end
|
data/lib/backup.rb
CHANGED
@@ -1,12 +1,16 @@
|
|
1
1
|
# Load in Connectivity and Transfer Gems
|
2
2
|
require 'net/ssh'
|
3
3
|
require 'net/scp'
|
4
|
+
require 'net/ftp'
|
5
|
+
require 'net/sftp'
|
4
6
|
require 'aws/s3'
|
5
7
|
|
6
8
|
# Load in Adapters
|
7
9
|
require 'backup/adapters/base'
|
8
10
|
require 'backup/adapters/mysql'
|
11
|
+
require 'backup/adapters/postgresql'
|
9
12
|
require 'backup/adapters/archive'
|
13
|
+
require 'backup/adapters/custom'
|
10
14
|
|
11
15
|
# Load in Connectors
|
12
16
|
require 'backup/connection/s3'
|
@@ -14,14 +18,19 @@ require 'backup/connection/s3'
|
|
14
18
|
# Load in Storage
|
15
19
|
require 'backup/storage/s3'
|
16
20
|
require 'backup/storage/scp'
|
21
|
+
require 'backup/storage/ftp'
|
22
|
+
require 'backup/storage/sftp'
|
17
23
|
|
18
24
|
# Load in Backup Recorders
|
19
25
|
require 'backup/record/s3'
|
20
26
|
require 'backup/record/scp'
|
27
|
+
require 'backup/record/ftp'
|
28
|
+
require 'backup/record/sftp'
|
21
29
|
|
22
30
|
# Load in Configuration
|
23
31
|
require 'backup/configuration/base'
|
24
32
|
require 'backup/configuration/adapter'
|
33
|
+
require 'backup/configuration/adapter_options'
|
25
34
|
require 'backup/configuration/storage'
|
26
35
|
require 'backup/configuration/helpers'
|
27
36
|
|
@@ -38,21 +47,30 @@ module Backup
|
|
38
47
|
class Setup
|
39
48
|
|
40
49
|
attr_accessor :trigger, :procedures, :procedure
|
41
|
-
|
50
|
+
|
51
|
+
# Sets the Trigger and All Available Procedures.
|
52
|
+
# Will not find a specific procedure if the "trigger" argument is set to false.
|
42
53
|
def initialize(trigger, procedures)
|
43
54
|
self.trigger = trigger
|
44
55
|
self.procedures = procedures
|
45
|
-
self.procedure = find_triggered_procedure
|
56
|
+
self.procedure = find_triggered_procedure unless trigger.eql?(false)
|
46
57
|
end
|
47
58
|
|
59
|
+
# Initializes one of the few adapters and start the backup process
|
48
60
|
def initialize_adapter
|
49
61
|
case procedure.adapter_name.to_sym
|
50
|
-
when :mysql
|
51
|
-
when :
|
52
|
-
|
62
|
+
when :mysql then Backup::Adapters::MySQL.new trigger, procedure
|
63
|
+
when :postgresql then Backup::Adapters::PostgreSQL.new trigger, procedure
|
64
|
+
when :archive then Backup::Adapters::Archive.new trigger, procedure
|
65
|
+
when :custom then Backup::Adapters::Custom.new trigger, procedure
|
66
|
+
else raise "Unknown Adapter: \"#{procedure.adapter_name}\"."
|
53
67
|
end
|
54
68
|
end
|
55
|
-
|
69
|
+
|
70
|
+
# Scans through all the backup settings and returns the backup setting
|
71
|
+
# that was specified in the "trigger" argument.
|
72
|
+
# If an non-existing trigger is specified, it will raise an error and display
|
73
|
+
# all the available triggers.
|
56
74
|
def find_triggered_procedure
|
57
75
|
procedures.each do |procedure|
|
58
76
|
if procedure.trigger.eql?(trigger)
|
@@ -2,18 +2,32 @@ module Backup
|
|
2
2
|
module Adapters
|
3
3
|
class Archive < Backup::Adapters::Base
|
4
4
|
|
5
|
-
attr_accessor :archived_file, :compressed_file, :encrypted_file
|
5
|
+
attr_accessor :archived_file, :compressed_file, :encrypted_file
|
6
6
|
|
7
7
|
# Initializes the Backup Process
|
8
|
+
#
|
9
|
+
# This will first load in any prefixed settings from the Backup::Adapters::Base
|
10
|
+
# Then it will add it's own settings.
|
11
|
+
#
|
12
|
+
# First it will archive and compress every folder/file
|
13
|
+
# Then it will optionally encrypt the backed up file
|
14
|
+
# Then it will store it to the specified storage location
|
15
|
+
# Then it will record the data to the database
|
16
|
+
# Once this is all done, all the temporary files will be removed
|
17
|
+
#
|
18
|
+
# Wrapped inside of begin/ensure/end block to ensure the deletion of any files in the tmp directory
|
8
19
|
def initialize(trigger, procedure)
|
9
20
|
super
|
10
21
|
load_settings
|
11
22
|
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
23
|
+
begin
|
24
|
+
targz
|
25
|
+
encrypt
|
26
|
+
store
|
27
|
+
record
|
28
|
+
ensure
|
29
|
+
remove_tmp_files
|
30
|
+
end
|
17
31
|
end
|
18
32
|
|
19
33
|
private
|
@@ -38,11 +52,9 @@ module Backup
|
|
38
52
|
|
39
53
|
# Loads the initial settings
|
40
54
|
def load_settings
|
41
|
-
self.
|
42
|
-
self.password = procedure.get_adapter_configuration.attributes['password']
|
43
|
-
self.database = procedure.get_adapter_configuration.attributes['database']
|
55
|
+
self.trigger = procedure.trigger
|
44
56
|
|
45
|
-
self.archived_file = "#{timestamp}
|
57
|
+
self.archived_file = "#{timestamp}.#{trigger.gsub(' ', '-')}.tar"
|
46
58
|
self.compressed_file = "#{archived_file}.gz"
|
47
59
|
self.encrypted_file = "#{compressed_file}.enc"
|
48
60
|
self.final_file = compressed_file
|
data/lib/backup/adapters/base.rb
CHANGED
@@ -19,7 +19,7 @@ module Backup
|
|
19
19
|
self.trigger = trigger
|
20
20
|
self.procedure = procedure
|
21
21
|
self.timestamp = Time.now.strftime("%Y%m%d%H%M%S")
|
22
|
-
self.tmp_path =
|
22
|
+
self.tmp_path = File.join(RAILS_ROOT.gsub(' ', '\ '), 'tmp', 'backup', trigger)
|
23
23
|
self.encrypt_with_password = procedure.attributes['encrypt_with_password']
|
24
24
|
self.keep_backups = procedure.attributes['keep_backups']
|
25
25
|
create_tmp_folder
|
@@ -32,21 +32,25 @@ module Backup
|
|
32
32
|
|
33
33
|
# Removes the files inside the temporary folder
|
34
34
|
def remove_tmp_files
|
35
|
-
%x{ rm #{tmp_path}
|
35
|
+
%x{ rm #{File.join(tmp_path, '*')} }
|
36
36
|
end
|
37
37
|
|
38
38
|
# Initializes the storing process depending on the store settings
|
39
39
|
# Options:
|
40
40
|
# Amazon (S3)
|
41
41
|
# Remote Server (SCP)
|
42
|
+
# Remote Server (FTP)
|
43
|
+
# Remote Server (SFTP)
|
42
44
|
def store
|
43
45
|
case procedure.storage_name.to_sym
|
44
46
|
when :s3 then Backup::Storage::S3.new(self)
|
45
47
|
when :scp then Backup::Storage::SCP.new(self)
|
48
|
+
when :ftp then Backup::Storage::FTP.new(self)
|
49
|
+
when :sftp then Backup::Storage::SFTP.new(self)
|
46
50
|
end
|
47
51
|
end
|
48
52
|
|
49
|
-
# Records data on every individual file to the
|
53
|
+
# Records data on every individual file to the database
|
50
54
|
def record
|
51
55
|
case procedure.storage_name.to_sym
|
52
56
|
when :s3
|
@@ -57,6 +61,14 @@ module Backup
|
|
57
61
|
record = Backup::Record::SCP.new
|
58
62
|
record.load_adapter(self)
|
59
63
|
record.save
|
64
|
+
when :ftp
|
65
|
+
record = Backup::Record::FTP.new
|
66
|
+
record.load_adapter(self)
|
67
|
+
record.save
|
68
|
+
when :sftp
|
69
|
+
record = Backup::Record::SFTP.new
|
70
|
+
record.load_adapter(self)
|
71
|
+
record.save
|
60
72
|
end
|
61
73
|
end
|
62
74
|
|
@@ -0,0 +1,74 @@
|
|
1
|
+
module Backup
|
2
|
+
module Adapters
|
3
|
+
class Custom < Backup::Adapters::Base
|
4
|
+
|
5
|
+
attr_accessor :archived_file, :compressed_file, :encrypted_file, :commands
|
6
|
+
|
7
|
+
# Initializes the Backup Process
|
8
|
+
#
|
9
|
+
# This will first load in any prefixed settings from the Backup::Adapters::Base
|
10
|
+
# Then it will add it's own settings.
|
11
|
+
#
|
12
|
+
# First it will execute any given commands
|
13
|
+
# Then it will archive and compress every folder/file
|
14
|
+
# Then it will optionally encrypt the backed up file
|
15
|
+
# Then it will store it to the specified storage location
|
16
|
+
# Then it will record the data to the database
|
17
|
+
# Once this is all done, all the temporary files will be removed
|
18
|
+
#
|
19
|
+
# Wrapped inside of begin/ensure/end block to ensure the deletion of any files in the tmp directory
|
20
|
+
def initialize(trigger, procedure)
|
21
|
+
super
|
22
|
+
load_settings
|
23
|
+
|
24
|
+
begin
|
25
|
+
execute_commands
|
26
|
+
targz
|
27
|
+
encrypt
|
28
|
+
store
|
29
|
+
record
|
30
|
+
ensure
|
31
|
+
remove_tmp_files
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
private
|
36
|
+
|
37
|
+
# Executes the commands
|
38
|
+
def execute_commands
|
39
|
+
if commands.is_a?(Array)
|
40
|
+
commands.each do |command|
|
41
|
+
%x{ #{command.gsub(':tmp_path', tmp_path)} }
|
42
|
+
end
|
43
|
+
elsif commands.is_a?(String)
|
44
|
+
%x{ #{commands.gsub(':tmp_path', tmp_path)} }
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
# Archives and Compresses
|
49
|
+
def targz
|
50
|
+
%x{ tar -czf #{File.join(tmp_path, compressed_file)} #{File.join(tmp_path, '*')} }
|
51
|
+
end
|
52
|
+
|
53
|
+
# Encrypts the archive file
|
54
|
+
def encrypt
|
55
|
+
if encrypt_with_password.is_a?(String)
|
56
|
+
%x{ openssl enc -des-cbc -in #{File.join(tmp_path, compressed_file)} -out #{File.join(tmp_path, encrypted_file)} -k #{encrypt_with_password} }
|
57
|
+
self.final_file = encrypted_file
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
# Loads the initial settings
|
62
|
+
def load_settings
|
63
|
+
self.trigger = procedure.trigger
|
64
|
+
self.commands = procedure.get_adapter_configuration.attributes['commands']
|
65
|
+
|
66
|
+
self.archived_file = "#{timestamp}.#{trigger.gsub(' ', '-')}.tar"
|
67
|
+
self.compressed_file = "#{archived_file}.gz"
|
68
|
+
self.encrypted_file = "#{compressed_file}.enc"
|
69
|
+
self.final_file = compressed_file
|
70
|
+
end
|
71
|
+
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
@@ -2,25 +2,39 @@ module Backup
|
|
2
2
|
module Adapters
|
3
3
|
class MySQL < Backup::Adapters::Base
|
4
4
|
|
5
|
-
attr_accessor :dumped_file, :compressed_file, :encrypted_file, :user, :password, :database
|
5
|
+
attr_accessor :dumped_file, :compressed_file, :encrypted_file, :user, :password, :database, :skip_tables, :host, :port, :socket
|
6
6
|
|
7
7
|
# Initializes the Backup Process
|
8
|
+
#
|
9
|
+
# This will first load in any prefixed settings from the Backup::Adapters::Base
|
10
|
+
# Then it will add it's own settings.
|
11
|
+
#
|
12
|
+
# First it will create a compressed MySQL dump
|
13
|
+
# Then it will optionally encrypt the backed up file
|
14
|
+
# Then it will store it to the specified storage location
|
15
|
+
# Then it will record the data to the database
|
16
|
+
# Once this is all done, all the temporary files will be removed
|
17
|
+
#
|
18
|
+
# Wrapped inside of begin/ensure/end block to ensure the deletion of any files in the tmp directory
|
8
19
|
def initialize(trigger, procedure)
|
9
20
|
super
|
10
21
|
load_settings
|
11
22
|
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
23
|
+
begin
|
24
|
+
mysqldump
|
25
|
+
encrypt
|
26
|
+
store
|
27
|
+
record
|
28
|
+
ensure
|
29
|
+
remove_tmp_files
|
30
|
+
end
|
17
31
|
end
|
18
32
|
|
19
33
|
private
|
20
34
|
|
21
35
|
# Dumps and Compresses the MySQL file
|
22
36
|
def mysqldump
|
23
|
-
%x{ mysqldump
|
37
|
+
%x{ mysqldump -u #{user} --password='#{password}' #{options} #{database} #{tables_to_skip} | gzip -f --best > #{File.join(tmp_path, compressed_file)} }
|
24
38
|
end
|
25
39
|
|
26
40
|
# Encrypts the MySQL file
|
@@ -33,16 +47,42 @@ module Backup
|
|
33
47
|
|
34
48
|
# Loads the initial settings
|
35
49
|
def load_settings
|
36
|
-
self.
|
37
|
-
|
38
|
-
|
50
|
+
self.trigger = procedure.trigger
|
51
|
+
|
52
|
+
%w(user password database skip_tables).each do |attribute|
|
53
|
+
send(:"#{attribute}=", procedure.get_adapter_configuration.attributes[attribute])
|
54
|
+
end
|
55
|
+
|
56
|
+
%w(host port socket).each do |attribute|
|
57
|
+
send(:"#{attribute}=", procedure.get_adapter_configuration.get_options.attributes[attribute])
|
58
|
+
end
|
39
59
|
|
40
|
-
self.dumped_file = "#{timestamp}.#{
|
60
|
+
self.dumped_file = "#{timestamp}.#{trigger.gsub(' ', '-')}.sql"
|
41
61
|
self.compressed_file = "#{dumped_file}.gz"
|
42
62
|
self.encrypted_file = "#{compressed_file}.enc"
|
43
63
|
self.final_file = compressed_file
|
44
64
|
end
|
45
65
|
|
66
|
+
# Returns a list of options in MySQL syntax
|
67
|
+
def options
|
68
|
+
options = String.new
|
69
|
+
options += " --host='#{host}' " unless host.blank?
|
70
|
+
options += " --port='#{port}' " unless port.blank?
|
71
|
+
options += " --socket='#{socket}' " unless socket.blank?
|
72
|
+
options
|
73
|
+
end
|
74
|
+
|
75
|
+
# Returns a list of tables to skip in MySQL syntax
|
76
|
+
def tables_to_skip
|
77
|
+
if skip_tables.is_a?(Array)
|
78
|
+
skip_tables.map {|table| " --ignore-table='#{database}.#{table}' "}
|
79
|
+
elsif skip_tables.is_a?(String)
|
80
|
+
" --ignore-table='#{database}.#{skip_tables}' "
|
81
|
+
else
|
82
|
+
""
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
46
86
|
end
|
47
87
|
end
|
48
88
|
end
|
@@ -0,0 +1,88 @@
|
|
1
|
+
module Backup
|
2
|
+
module Adapters
|
3
|
+
class PostgreSQL < Backup::Adapters::Base
|
4
|
+
|
5
|
+
attr_accessor :dumped_file, :compressed_file, :encrypted_file, :user, :password, :database, :skip_tables, :host, :port, :socket
|
6
|
+
|
7
|
+
# Initializes the Backup Process
|
8
|
+
#
|
9
|
+
# This will first load in any prefixed settings from the Backup::Adapters::Base
|
10
|
+
# Then it will add it's own settings.
|
11
|
+
#
|
12
|
+
# First it will create a compressed PostgreSQL dump
|
13
|
+
# Then it will optionally encrypt the backed up file
|
14
|
+
# Then it will store it to the specified storage location
|
15
|
+
# Then it will record the data to the database
|
16
|
+
# Once this is all done, all the temporary files will be removed
|
17
|
+
#
|
18
|
+
# Wrapped inside of begin/ensure/end block to ensure the deletion of any files in the tmp directory
|
19
|
+
def initialize(trigger, procedure)
|
20
|
+
super
|
21
|
+
load_settings
|
22
|
+
|
23
|
+
begin
|
24
|
+
pg_dump
|
25
|
+
encrypt
|
26
|
+
store
|
27
|
+
record
|
28
|
+
ensure
|
29
|
+
remove_tmp_files
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
private
|
34
|
+
|
35
|
+
# Dumps and Compresses the PostgreSQL file
|
36
|
+
def pg_dump
|
37
|
+
%x{ pg_dump -U #{user} #{options} #{tables_to_skip} #{database} | gzip -f --best > #{File.join(tmp_path, compressed_file)} }
|
38
|
+
end
|
39
|
+
|
40
|
+
# Encrypts the PostgreSQL file
|
41
|
+
def encrypt
|
42
|
+
if encrypt_with_password.is_a?(String)
|
43
|
+
%x{ openssl enc -des-cbc -in #{File.join(tmp_path, compressed_file)} -out #{File.join(tmp_path, encrypted_file)} -k #{encrypt_with_password} }
|
44
|
+
self.final_file = encrypted_file
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
# Loads the initial settings
|
49
|
+
def load_settings
|
50
|
+
self.trigger = procedure.trigger
|
51
|
+
|
52
|
+
%w(user password database skip_tables).each do |attribute|
|
53
|
+
send(:"#{attribute}=", procedure.get_adapter_configuration.attributes[attribute])
|
54
|
+
end
|
55
|
+
|
56
|
+
%w(host port socket).each do |attribute|
|
57
|
+
send(:"#{attribute}=", procedure.get_adapter_configuration.get_options.attributes[attribute])
|
58
|
+
end
|
59
|
+
|
60
|
+
self.dumped_file = "#{timestamp}.#{trigger.gsub(' ', '-')}.sql"
|
61
|
+
self.compressed_file = "#{dumped_file}.gz"
|
62
|
+
self.encrypted_file = "#{compressed_file}.enc"
|
63
|
+
self.final_file = compressed_file
|
64
|
+
end
|
65
|
+
|
66
|
+
# Returns a list of options in PostgreSQL syntax
|
67
|
+
def options
|
68
|
+
options = String.new
|
69
|
+
options += " --port='#{port}' " unless port.blank?
|
70
|
+
options += " --host='#{host}' " unless host.blank?
|
71
|
+
options += " --host='#{socket}' " unless socket.blank? unless options.include?('--host=')
|
72
|
+
options
|
73
|
+
end
|
74
|
+
|
75
|
+
# Returns a list of tables to skip in PostgreSQL syntax
|
76
|
+
def tables_to_skip
|
77
|
+
if skip_tables.is_a?(Array)
|
78
|
+
skip_tables.map {|table| " -T \"#{table}\" "}
|
79
|
+
elsif skip_tables.is_a?(String)
|
80
|
+
" -T \"#{skip_tables}\" "
|
81
|
+
else
|
82
|
+
""
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|