wordpress-deploy 1.0.0.alpha2 → 1.0.0.rc1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (40) hide show
  1. data/.gitignore +7 -1
  2. data/Guardfile +1 -16
  3. data/README.md +56 -0
  4. data/lib/wordpress_deploy.rb +43 -9
  5. data/lib/wordpress_deploy/cli/helpers.rb +6 -3
  6. data/lib/wordpress_deploy/cli/utility.rb +56 -33
  7. data/lib/wordpress_deploy/config.rb +77 -0
  8. data/lib/wordpress_deploy/database/mysql.rb +281 -20
  9. data/lib/wordpress_deploy/environment.rb +85 -43
  10. data/lib/wordpress_deploy/environments.rb +89 -0
  11. data/lib/wordpress_deploy/logger.rb +3 -3
  12. data/lib/wordpress_deploy/{transfer_protocols → storage}/ftp.rb +52 -116
  13. data/lib/wordpress_deploy/storage/local.rb +12 -0
  14. data/lib/wordpress_deploy/version.rb +1 -1
  15. data/lib/wordpress_deploy/wordpress/salts.rb +68 -0
  16. data/spec/data/blue.rb +52 -0
  17. data/spec/data/development.rb +49 -0
  18. data/spec/data/green.rb +52 -0
  19. data/spec/data/production.rb +52 -0
  20. data/spec/data/red.rb +52 -0
  21. data/spec/data/wp-config.php +90 -0
  22. data/spec/spec_helper.rb +16 -5
  23. data/spec/wordpress_deploy/cli/utility_spec.rb +48 -0
  24. data/spec/{environment_spec.rb → wordpress_deploy/config_spec.rb} +9 -7
  25. data/spec/wordpress_deploy/database/mysql_spec.rb +147 -0
  26. data/spec/wordpress_deploy/environment_spec.rb +96 -0
  27. data/spec/wordpress_deploy/environments_spec.rb +65 -0
  28. data/spec/wordpress_deploy/storage/ftp_spec.rb +58 -0
  29. data/spec/wordpress_deploy/storage/local_spec.rb +0 -0
  30. data/spec/wordpress_deploy/wordpress/salts_spec.rb +70 -0
  31. data/{spec/data/wp-config-sample.php → templates/wp-config.erb} +17 -17
  32. data/wordpress_deploy.gemspec +7 -6
  33. metadata +64 -30
  34. data/Gemfile.lock +0 -83
  35. data/lib/wordpress_deploy/wordpress/configuration.rb +0 -196
  36. data/spec/data/ftp.yml +0 -4
  37. data/spec/data/wp-config.yml +0 -128
  38. data/spec/database/mysql_spec.rb +0 -93
  39. data/spec/transfer_protocols/ftp_spec.rb +0 -193
  40. data/spec/wordpress/configuration_spec.rb +0 -202
data/.gitignore CHANGED
@@ -12,6 +12,8 @@ test/tmp
12
12
  test/version_tmp
13
13
  tmp
14
14
 
15
+ *.swp
16
+
15
17
  # YARD artifacts
16
18
  .yardoc
17
19
  _yardoc
@@ -20,8 +22,12 @@ doc/
20
22
  # Mac files
21
23
  .DS_Store
22
24
 
25
+ # Development gems
26
+ Gemfile.lock
27
+
23
28
  # Spec data made during tests
24
- spec/data/wp-config.php
29
+ spec/data/*.sql
25
30
  *.log
26
31
  config/
27
32
  site/
33
+ sql/
data/Guardfile CHANGED
@@ -3,22 +3,7 @@
3
3
 
4
4
  guard 'rspec', :version => 2 do
5
5
  watch(%r{^spec/.+_spec\.rb$})
6
- watch(%r{^lib/wordpress_deploy/(.+)\.rb$}) { |m| "spec/#{m[1]}_spec.rb" }
6
+ watch(%r{^lib/(.+)\.rb$}) { |m| "spec/#{m[1]}_spec.rb" }
7
7
  watch('spec/spec_helper.rb') { "spec" }
8
-
9
- # Rails example
10
- #watch(%r{^app/(.+)\.rb$}) { |m| "spec/#{m[1]}_spec.rb" }
11
- #watch(%r{^app/(.*)(\.erb|\.haml)$}) { |m| "spec/#{m[1]}#{m[2]}_spec.rb" }
12
- #watch(%r{^app/controllers/(.+)_(controller)\.rb$}) { |m| ["spec/routing/#{m[1]}_routing_spec.rb", "spec/#{m[2]}s/#{m[1]}_#{m[2]}_spec.rb", "spec/acceptance/#{m[1]}_spec.rb"] }
13
- #watch(%r{^spec/support/(.+)\.rb$}) { "spec" }
14
- #watch('config/routes.rb') { "spec/routing" }
15
- #watch('app/controllers/application_controller.rb') { "spec/controllers" }
16
-
17
- # Capybara request specs
18
- #watch(%r{^app/views/(.+)/.*\.(erb|haml)$}) { |m| "spec/requests/#{m[1]}_spec.rb" }
19
-
20
- # Turnip features and steps
21
- #watch(%r{^spec/acceptance/(.+)\.feature$})
22
- #watch(%r{^spec/acceptance/steps/(.+)_steps\.rb$}) { |m| Dir[File.join("**/#{m[1]}.feature")][0] || 'spec/acceptance' }
23
8
  end
24
9
 
data/README.md CHANGED
@@ -35,3 +35,59 @@ Usage
35
35
  -----
36
36
 
37
37
  wp-deploy help
38
+
39
+
40
+ ```ruby
41
+ ##
42
+ # This is an example of a default WordpressDeploy configuration file. The
43
+ # values here are examples to show you what to do.
44
+ WordpressDeploy::Environment.new(:red) do
45
+
46
+ base_url "localhost"
47
+
48
+ ##
49
+ # Connection and settings for the MySQL database that wordpress
50
+ # connects to
51
+ database do
52
+ name "red"
53
+ user "red_user"
54
+ password "Bun__huPEMeBreM6tebRAp@eguzuQExe"
55
+ host "hanerutherford.biz"
56
+ charset "utf8"
57
+ collate ""
58
+
59
+ ##
60
+ # If this parameter is not defined wp_
61
+ # is assumed.
62
+ table_prefix "wp_";
63
+ end
64
+
65
+ ##
66
+ # Authentication Unique Keys and Salts
67
+ # https://api.wordpress.org/secret-key/1.1/salt/
68
+ # If no salts are supplied they will be generated automatically
69
+ #
70
+ # NOTE This entire block is optional
71
+ salts do
72
+ auth_key '*oH{(q=`tIzdNJKUk$XfHNNjKd$W=f$S`CtD.,;x0R}$/A,}]!+q0>>QfB#.Bsw]'
73
+ secure_auth_key '{yg|7Q*j-?$%`b|Z!+5U,pvM,eA0+$/ruprp.mO[;|fExU:n0,-!at0+3UY@;h`X'
74
+ logged_in_key 'k]N 9I<-rZq#k Xg)IPhv$E*ktbD7Z_AtI){U;(P;0r#LJlYncEr%8v9tG`>BHU+'
75
+ nonce_key ' /w9->::-YB Xa#lf%TPH+cIf?]Ru4OfKGF2h8PHsa)2,n-~kRJ<[slUg<GZ Asx'
76
+ auth_salt 'VYwGGP,#|9P[5RCUTdv2c8)`^{dotU0fWrU`JE9qq^n=F4//e)fCs<HF6sd>~yjW'
77
+ secure_auth_salt 'ok}@vSs=n6%_%UCO|&[?Jc;,-,.#Q3}zR4ej%IoAL7RavTN/Xe,UrQ4)p}onRie0'
78
+ logged_in_salt 'Z!,C*:Q_I9A`[pJm-b0Z/(Gm2qvK8>0~| T&)lM+sxG.OdEmgHbAGF&(^>2.rDGW'
79
+ nonce_salt 'ay)${bFV=F1KH[`NZ+W+Zk?Hc:@}jN}Ec)+Zn[F1fyP,mwi|@tk/(1hdp[G2F%os'
80
+ end
81
+
82
+ ##
83
+ # Block defines the settings for the transfer of files
84
+ # to this configuration.
85
+ transfer :Ftp do
86
+ host "ftp.hanerutherford.biz"
87
+ user "red_user"
88
+ password "Bun__huPEMeBreM6tebRAp@eguzuQExe"
89
+ destination "/html"
90
+ end
91
+
92
+ end
93
+ ```
@@ -1,16 +1,49 @@
1
1
  require "thor"
2
2
  require "open3"
3
3
  require "fileutils"
4
+ require "yaml"
5
+
6
+ class Hash
7
+
8
+ def find_and_replace!(find, replace)
9
+ RecursiveReplace.find_and_replace!(find, replace, self)
10
+ end
11
+
12
+ end
13
+
14
+ class RecursiveReplace
15
+
16
+ def self.find_and_replace!(find, replace, obj)
17
+ m = "find_and_replace_#{obj.class}!"
18
+ send(m, find, replace, obj) if respond_to? m, true
19
+ end
20
+
21
+ private
22
+
23
+ def self.find_and_replace_Hash!(find, replace, hash)
24
+ hash.each { |k,v| find_and_replace!(find, replace, v) }
25
+ end
26
+
27
+ def self.find_and_replace_Array!(find, replace, arr)
28
+ arr.each { |x| find_and_replace!(find, replace, x) }
29
+ end
30
+
31
+ def self.find_and_replace_String!(find, replace, str)
32
+ str.gsub!(/#{find}/, replace)
33
+ end
34
+
35
+ end
4
36
 
5
37
  module WordpressDeploy
6
38
  ##
7
39
  # WordpressDeploy's internal paths
8
40
  #
9
- LIBRARY_PATH = File.join(File.dirname(__FILE__), 'wordpress_deploy')
10
- CLI_PATH = File.join(LIBRARY_PATH, 'cli')
11
- WORDPRESS_PATH = File.join(LIBRARY_PATH, 'wordpress')
12
- TRANSFER_PROTOCOLS_PATH = File.join(LIBRARY_PATH, 'transfer_protocols')
13
- DATABASE_PATH = File.join(LIBRARY_PATH, 'database')
41
+ LIBRARY_PATH = File.join(File.dirname(__FILE__), 'wordpress_deploy')
42
+ TEMPLATE_PATH = File.join(File.dirname(__FILE__), '..', 'templates')
43
+ CLI_PATH = File.join(LIBRARY_PATH, 'cli')
44
+ WORDPRESS_PATH = File.join(LIBRARY_PATH, 'wordpress')
45
+ STORAGE_PATH = File.join(LIBRARY_PATH, 'storage')
46
+ DATABASE_PATH = File.join(LIBRARY_PATH, 'database')
14
47
 
15
48
  module Cli
16
49
  autoload :Helpers, File.join(CLI_PATH, 'helpers')
@@ -18,18 +51,19 @@ module WordpressDeploy
18
51
  end
19
52
 
20
53
  module Wordpress
21
- autoload :Configuration, File.join(WORDPRESS_PATH, 'configuration')
54
+ autoload :Salts, File.join(WORDPRESS_PATH, 'salts')
22
55
  end
23
56
 
24
- module TransferProtocols
25
- autoload :Ftp, File.join(TRANSFER_PROTOCOLS_PATH, 'ftp')
57
+ module Storage
58
+ autoload :Ftp, File.join(STORAGE_PATH, 'ftp')
59
+ autoload :Local, File.join(STORAGE_PATH, 'local')
26
60
  end
27
61
 
28
62
  module Database
29
63
  autoload :MySql, File.join(DATABASE_PATH, 'mysql')
30
64
  end
31
65
 
32
- %w{version logger errors environment}.each do |klass|
66
+ %w{version logger errors config environments environment}.each do |klass|
33
67
  require File.join(LIBRARY_PATH, klass)
34
68
  end
35
69
  end
@@ -14,7 +14,7 @@ module WordpressDeploy
14
14
  # If the command fails to execute, or returns a non-zero exit status
15
15
  # an Error will be raised.
16
16
  #
17
- # Returns nil
17
+ # Returns STDOUT
18
18
  def run(command)
19
19
  name = command_name(command)
20
20
  Logger.debug "Running system utility '#{ name }'..."
@@ -47,7 +47,7 @@ module WordpressDeploy
47
47
  )
48
48
  end
49
49
 
50
- return nil
50
+ return out
51
51
  else
52
52
  raise Errors::Cli::SystemCallError, <<-EOS
53
53
  '#{ name }' Failed on #{ RUBY_PLATFORM }
@@ -69,7 +69,10 @@ module WordpressDeploy
69
69
  raise Errors::Cli::UtilityNotFoundError,
70
70
  'Utility Name Empty' if name.empty?
71
71
 
72
+ # Return the utility immediately if it has already been found
72
73
  path = UTILITY[name]
74
+ return path unless path.nil?
75
+
73
76
  err, ps = '', nil
74
77
  Open3.popen3 "which #{name}" do |stdin, stdout, stderr, wait_thr|
75
78
  stdin.close
@@ -78,7 +81,7 @@ module WordpressDeploy
78
81
 
79
82
  # Process::Status object returned
80
83
  ps = wait_thr.value
81
- end if path.nil?
84
+ end
82
85
 
83
86
  if !ps.nil? && ps.success?
84
87
  UTILITY[name] = path
@@ -9,24 +9,26 @@ module WordpressDeploy
9
9
  # These options apply to all commands
10
10
  class_option :root_dir, type: :string, default: '', aliases: '-r'
11
11
  class_option :wp_dir, type: :string, default: '', aliases: '-w'
12
- class_option :environment, type: :string, default: 'production', aliases: '-e'
12
+ class_option :config_dir, type: :string, default: '', aliases: '-c'
13
+ class_option :sql_dir, type: :string, default: '', aliases: '-s'
13
14
  class_option :verbose, type: :boolean, default: false, aliases: '-v'
14
15
 
15
-
16
- desc "generate", "Generate the wp-config.php file. Accepted environments are production or development."
17
- def generate
18
- ##
16
+ desc "config ENVIRONMENT", "Generate the wp-config.php file for the specified environment."
17
+ def config(environment)
19
18
  # Set Logger into verbose mode (if the user requested it)
20
19
  Logger.verbose = options[:verbose]
21
20
 
22
21
  # Set environment options
23
- Environment.set_options options
22
+ Config.set_options options
23
+
24
+ # Load ALL the available environments
25
+ WordpressDeploy::Environments.load
24
26
 
25
- # Create a configuration file
26
- config = Wordpress::Configuration.new
27
+ # Get the Environment the user requested
28
+ env = WordpressDeploy::Environments.find environment.to_sym
27
29
 
28
30
  # Save the configuration file
29
- config.save!
31
+ env.save_wp_config
30
32
  rescue => err
31
33
  Logger.error Errors::Cli::Utility::Error.wrap(err)
32
34
 
@@ -34,62 +36,83 @@ module WordpressDeploy
34
36
  exit(1)
35
37
  end
36
38
 
37
- desc "deploy", "Deploy via FTP to configuration hostname."
38
- def deploy
39
- ##
39
+ desc "deploy FROM TO", <<-EOS
40
+ Deploy Wordpress onto the TO environment.
41
+
42
+ This is achieved by first generating the appropriate wp-config.php file for the
43
+ desired environment. This wp-config.php, along with all other files within the
44
+ wp_dir, are then transmitted to the configured TO environment.
45
+
46
+ Next, the FROM database is backed up into the sql_dir, and then sent to the
47
+ configured TO environment. Finally, all records in the TO database are scrubbed
48
+ to be relative to the new hostname configured for the environment (this
49
+ includes PHP serialized strings).
50
+ EOS
51
+ def deploy(from, to)
40
52
  # Set Logger into verbose mode (if the user requested it)
41
53
  Logger.verbose = options[:verbose]
42
54
 
43
55
  # Set environment options
44
- Environment.set_options options
56
+ Config.set_options options
45
57
 
46
- # Create a new FTP client for sending the files
47
- ftp_client = TransferProtocols::Ftp.new options[:environment]
58
+ # Load ALL the available environments
59
+ WordpressDeploy::Environments.load
48
60
 
49
- # Now transmit the files
50
- ftp_client.transmit!
61
+ # Get the Environment the user requested
62
+ from = WordpressDeploy::Environments.find from.to_sym
63
+ to = WordpressDeploy::Environments.find to.to_sym
51
64
 
52
65
  rescue => err
53
66
  Logger.error Errors::Cli::Utility::Error.wrap(err)
54
67
 
55
68
  # Exit with an error
56
69
  exit(1)
57
- ensure
58
- puts "Closing connection.".colorize(color: :red, background: :yellow) if ftp_client.close
59
70
  end
60
71
 
61
- desc "backup", "Pull down the remote files over FTP."
62
- def backup
63
- ##
72
+ desc "backup ENVIRONMENT", "Call mysqldump on the database specified by ENVIRONMENT"
73
+ def backup(environment)
64
74
  # Set Logger into verbose mode (if the user requested it)
65
75
  Logger.verbose = options[:verbose]
66
76
 
67
77
  # Set environment options
68
- Environment.set_options options
78
+ Config.set_options options
79
+
80
+ # Load ALL the available environments
81
+ WordpressDeploy::Environments.load
69
82
 
70
- # Create a new FTP client for receiving the files
71
- ftp_client = TransferProtocols::Ftp.new options[:environment]
83
+ # Get the Environment the user requested
84
+ env = WordpressDeploy::Environments.find environment.to_sym
72
85
 
73
- # Now receive the files
74
- ftp_client.receive!
86
+ # Backup the database to the sql_dir
87
+ env.database.save!
75
88
 
76
89
  rescue => err
77
90
  Logger.error Errors::Cli::Utility::Error.wrap(err)
78
91
 
79
92
  # Exit with an error
80
93
  exit(1)
81
- ensure
82
- puts "Closing connection.".colorize(color: :red, background: :yellow) if ftp_client.close
83
94
  end
84
95
 
85
- desc "mirror", "Mirror database between two locations"
86
- def mirror(from, to)
87
- ##
96
+ desc "transmit ENVIRONMENT", "Transmit the files in wp_dir"
97
+ def transmit(environment)
88
98
  # Set Logger into verbose mode (if the user requested it)
89
99
  Logger.verbose = options[:verbose]
90
100
 
91
101
  # Set environment options
92
- Environment.set_options options
102
+ Config.set_options options
103
+
104
+ # Load ALL the available environments
105
+ WordpressDeploy::Environments.load
106
+
107
+ # Get the Environment the user requested
108
+ env = WordpressDeploy::Environments.find environment.to_sym
109
+
110
+ # Save the configuration file
111
+ env.save_wp_config
112
+
113
+ # Send the files in wp_dir
114
+ env.transfer.transmit!
115
+
93
116
  rescue => err
94
117
  Logger.error Errors::Cli::Utility::Error.wrap(err)
95
118
 
@@ -0,0 +1,77 @@
1
+ module WordpressDeploy
2
+ ##
3
+ # Config defines all of the locations of input and
4
+ # output files. Specifically, the locations of the test
5
+ # definitions, the locations of the test results, and
6
+ # the locations of the build applications.
7
+ module Config
8
+
9
+ ##
10
+ # Setup required paths based on the given options
11
+ def self.set_options(options = {})
12
+ options.each do |option, value|
13
+ method = "#{option}="
14
+ send(method, value) if respond_to? method and !value.empty?
15
+ end
16
+ end
17
+
18
+ def self.logging=(new_log)
19
+ # Only set @@logging if new_log is a boolean
20
+ if !!new_log == new_log
21
+ @@logging = new_log
22
+ else
23
+ @@logging = false
24
+ end
25
+ end
26
+
27
+ def self.logging?
28
+ @@logging ||= false
29
+ @@logging
30
+ end
31
+
32
+ def self.root_dir=(new_root)
33
+ @@root_dir = new_root
34
+ end
35
+
36
+ def self.root_dir
37
+ @@root_dir ||= Dir.pwd
38
+ File.expand_path @@root_dir
39
+ end
40
+
41
+ def self.config_dir=(new_config_dir)
42
+ @@config_dir = new_config_dir
43
+ end
44
+
45
+ def self.config_dir
46
+ @@config_dir ||= "config"
47
+ File.expand_path File.join(root_dir, @@config_dir)
48
+ end
49
+
50
+ def self.wp_dir=(new_wp_dir)
51
+ @@wp_dir = new_wp_dir
52
+ end
53
+
54
+ def self.wp_dir
55
+ @@wp_dir ||= "site"
56
+ File.expand_path File.join(root_dir, @@wp_dir)
57
+ end
58
+
59
+ def self.sql_dir=(new_sql_dir)
60
+ @@sql_dir = new_sql_dir
61
+ end
62
+
63
+ def self.sql_dir
64
+ @@sql_dir ||= "sql"
65
+ File.expand_path File.join(root_dir, @@sql_dir)
66
+ end
67
+
68
+ def self.log_file
69
+ @@log_file ||= "#{Time.now.strftime("%Y_%m_%d_%H_%M_%S")}.log"
70
+ File.expand_path File.join(root_dir, @@log_file)
71
+ end
72
+
73
+ def self.clean!
74
+ FileUtils.rm Dir.glob(File.join(root_dir, "*.log"))
75
+ end
76
+ end
77
+ end
@@ -1,4 +1,6 @@
1
- require 'tmpdir'
1
+ require 'tempfile'
2
+ require 'mysql2'
3
+ require 'php_serialize'
2
4
 
3
5
  module WordpressDeploy
4
6
  module Database
@@ -6,37 +8,296 @@ module WordpressDeploy
6
8
  class MySql
7
9
  include WordpressDeploy::Cli::Helpers
8
10
 
9
- attr_reader :configuration
10
-
11
11
  def initialize
12
- @yaml = YAML.load_file(File.join(Environment.config_dir, "wp-config.yml"))
12
+ @user ||= "root"
13
+ @password ||= ""
14
+
15
+ @host ||= "localhost"
16
+ @port ||= 3306
17
+ @socket ||= ""
18
+ @name ||= "wordpress"
19
+
20
+ @has_port ||= true
21
+ @has_socket ||= false
13
22
  end
14
23
 
15
- def mysqldump
16
- "#{utility("mysqldump")} #{arguments}"
24
+ ##
25
+ # Name of the database (DB_NAME)
26
+ def name(new_name = nil)
27
+ @name = new_name.to_s unless new_name.nil?
28
+ @name
17
29
  end
18
30
 
19
- def configuration=(new_config)
20
- @configuration = new_config if new_config.instance_of? WordpressDeploy::Wordpress::Configuration
31
+ ##
32
+ # User credentials for the specified database
33
+ def user(new_user = nil)
34
+ @user = new_user.to_s unless new_user.nil?
35
+ @user
21
36
  end
22
37
 
23
- private
38
+ ##
39
+ # Password credentials for the specified database
40
+ def password(new_password = nil)
41
+ @password = new_password.to_s unless new_password.nil?
42
+ @password
43
+ end
44
+
45
+ ##
46
+ # Get just the hostname from DB_HOST. Only different from
47
+ # DB_HOST if DB_HOST has a socket or a port number in it.
48
+ def host(new_host = nil)
49
+ unless new_host.nil?
50
+ match = /(?<host>.*?)(?=:|\z)(:(?<socket>\/.*)|:(?<port>\d+))?/.match(new_host.to_s)
51
+ @host = match[:host].to_s unless match[:host].nil?
52
+
53
+ # Set the socket information
54
+ if @has_socket = !match[:socket].nil?
55
+ @has_socket = true
56
+ @socket = match[:socket]
57
+ end
58
+
59
+ # Set the port information
60
+ unless match[:port].nil?
61
+ @port = match[:port].to_i
62
+ end
63
+
64
+ # Has port is true; unless a socket was set
65
+ @has_port = !@has_socket
66
+ end
67
+
68
+ # return the host
69
+ @host
70
+ end
71
+
72
+ ##
73
+ # This value should be able to be plugged directly into
74
+ # DB_HOST int he wp-config.php file.
75
+ def wp_host
76
+ extra = nil
77
+ extra = ":#{socket}" if socket?
78
+ extra = ":#{port}" if port?
79
+ "#{host}#{extra}"
80
+ end
81
+
82
+ ##
83
+ # Extract just the port number from the DB_HOST
84
+ # configuration file. Or return the default port of 3306.
85
+ def port
86
+ @port
87
+ end
88
+
89
+ ##
90
+ # Does DB_HOST contain a port number? (it does if one was
91
+ # specified and it does not equal 3306; the default MySQL
92
+ # port number.
93
+ def port?
94
+ @has_port && port != 3306
95
+ end
96
+
97
+ ##
98
+ # Extract just the socket part from the DB_HOST
99
+ # configuration file. Or return an empty string if none.
100
+ def socket
101
+ @socket
102
+ end
103
+
104
+ ##
105
+ # Does DB_HOST contain a socket path?
106
+ def socket?
107
+ @has_socket
108
+ end
109
+
110
+ def charset(new_charset = nil)
111
+ @charset = new_charset.to_s unless new_charset.nil?
112
+ @charset
113
+ end
24
114
 
25
- def arguments
26
- host = configuration.host
27
- port = configuration.port
28
- username = configuration.DB_USER
29
- password = configuration.DB_PASSWORD
30
- db_name = configuration.DB_NAME
115
+ def collate(new_collate = nil)
116
+ @collate = new_collate.to_s unless new_collate.nil?
117
+ @collate
118
+ end
31
119
 
32
- "-P \"#{port}\" -h \"#{host}\" -u \"#{username}\" -p#{password} -B \"#{db_name}\""
120
+ def table_prefix(new_prefix = nil)
121
+ @prefix = new_prefix.to_s unless new_prefix.nil?
122
+ @prefix
123
+ end
124
+
125
+ ##
126
+ # The file that the instance would save to if
127
+ # save is called.
128
+ def file
129
+ File.join(Config.sql_dir, "#{name}.sql")
33
130
  end
34
131
 
35
132
  ##
36
- # A temporary directory for installing the executable to
37
- def tmp_dir
38
- @tmp_dir ||= Dir.mktmpdir
39
- File.expand_path(@tmp_dir)
133
+ # Save the database to a file locally.
134
+ #
135
+ # The database will be output into #file.
136
+ def save!
137
+ # Get the output from MySQL Dump
138
+ cmd = mysqldump
139
+ dump_str = run cmd
140
+
141
+ # Open the supplied file; or create a temporary one
142
+ file_io = File.new(file, 'w')
143
+
144
+ # Start writing to file
145
+ file_io.write(dump_str)
146
+
147
+ true
148
+ ensure
149
+ file_io.close unless file_io.nil?
150
+ end
151
+
152
+ ##
153
+ #
154
+ def send!(to_config_name)
155
+ # Check to see if there is a SQL file
156
+ if File.exists? file
157
+ # Create the 'to' configuration
158
+ mysql = self.class.new(to_config_name)
159
+
160
+ # Open the source sql file for reading
161
+ tmp_file = Tempfile.new(["#{to_config_name}", '.sql'])
162
+
163
+ # Write sql to tmpfile while changing the
164
+ # the CREATE DATABASE and USE commands to make sense for
165
+ # the 'to' configuration
166
+ sql_dump = File.read(file)
167
+ sql_dump.gsub!(/^USE\ `#{self.DB_NAME}`/, "USE `#{mysql.DB_NAME}`")
168
+ tmp_file.puts sql_dump
169
+
170
+ # Get the MySQL load command
171
+ cmd = mysqlload to_config_name, tmp_file.path
172
+
173
+ # Run the mysql command to load the mysqldump into
174
+ # the destination mysql instance
175
+ run cmd
176
+ end
177
+ ensure
178
+ # Delete the temp file unless it was never made
179
+ tmp_file.unlink unless tmp_file.nil?
180
+ end
181
+
182
+ ##
183
+ #
184
+ def migrate!(to_config_name)
185
+ mysql = self.class.new(to_config_name)
186
+
187
+ client = Mysql2::Client.new(
188
+ :host => mysql.db_hostname,
189
+ :username => mysql.DB_USER,
190
+ :password => mysql.DB_PASSWORD,
191
+ :port => mysql.db_port,
192
+ :database => mysql.DB_NAME,
193
+ #:socket = '/path/to/mysql.sock',
194
+ :encoding => mysql.DB_CHARSET
195
+ )
196
+
197
+ value_to_find = "localhost/~lindsey/huntsvillecrawfishboil.com"
198
+ value_to_replace = "huntsvillecrawfishboil.com"
199
+ escaped_value_to_find = client.escape(value_to_find)
200
+
201
+ # wp_options option_value
202
+ sql = <<-EOS
203
+ SELECT `option_id`, `option_value`
204
+ FROM `wp_options`
205
+ WHERE `option_value` REGEXP '#{escaped_value_to_find}';
206
+ EOS
207
+ wp_options = client.query(sql)
208
+ wp_options.each do |row|
209
+ row.each do |key, value|
210
+ if PHP.serialized?(value)
211
+ ruby_php = PHP.unserialize(value)
212
+ ruby_php.find_and_replace!(value_to_find, value_to_replace)
213
+ value.replace PHP.serialize(ruby_php)
214
+ else
215
+ value.gsub!(/#{value_to_find}/, value_to_replace) if value.instance_of? String
216
+ end
217
+ end
218
+
219
+ # Update the database
220
+ sql = <<-EOD
221
+ UPDATE `wp_options`
222
+ SET `option_value`='#{client.escape(row['option_value'])}'
223
+ WHERE `option_id` = #{row['option_id']};
224
+ EOD
225
+ Logger.debug sql
226
+ client.query(sql)
227
+ end
228
+
229
+ # wp_posts post_content, guid
230
+ sql = <<-EOS
231
+ SELECT `ID`, `post_content`, `guid`
232
+ FROM `wp_posts`
233
+ WHERE `post_content` REGEXP '#{escaped_value_to_find}'
234
+ AND `guid` REGEXP '#{escaped_value_to_find}';
235
+ EOS
236
+ wp_posts = client.query(sql)
237
+ wp_posts.each do |row|
238
+ row.each do |key, value|
239
+ if PHP.serialized?(value)
240
+ ruby_php = PHP.unserialize(value)
241
+ ruby_php.find_and_replace!(value_to_find, value_to_replace)
242
+ value.replace PHP.serialize(ruby_php)
243
+ else
244
+ value.gsub!(/#{value_to_find}/, value_to_replace) if value.instance_of? String
245
+ end
246
+ end
247
+ sql = <<-EOD
248
+ UPDATE `wp_posts`
249
+ SET `post_content` = '#{client.escape(row['post_content'])}',
250
+ `guid` = '#{client.escape(row['guid'])}'
251
+ WHERE `ID` = #{row['ID']};
252
+ EOD
253
+ Logger.debug sql
254
+ client.query(sql)
255
+ end
256
+
257
+ # wp_postmeta
258
+ sql = <<-EOS
259
+ SELECT `meta_id`, `meta_value`
260
+ FROM `wp_postmeta`
261
+ WHERE `meta_value` REGEXP '#{escaped_value_to_find}';
262
+ EOS
263
+ wp_postmeta = client.query(sql)
264
+ wp_postmeta.each do |row|
265
+ row.each do |key, value|
266
+ if PHP.serialized?(value)
267
+ ruby_php = PHP.unserialize(value)
268
+ ruby_php.find_and_replace!(value_to_find, value_to_replace)
269
+ value.replace PHP.serialize(ruby_php)
270
+ else
271
+ value.gsub!(/#{value_to_find}/, value_to_replace) if value.instance_of? String
272
+ end
273
+ end
274
+ sql = <<-EOD
275
+ UPDATE `wp_postmeta`
276
+ SET `meta_value` = '#{client.escape(row['meta_value'])}'
277
+ WHERE `meta_id` = #{row['meta_id']};
278
+ EOD
279
+ Logger.debug sql
280
+ client.query(sql)
281
+ end
282
+ end
283
+
284
+ private
285
+
286
+ def mysqldump
287
+ arguments = "-P \"#{port}\" -h \"#{host}\" -u \"#{user}\" -p\"#{password}\" -B \"#{name}\""
288
+ "#{utility("mysqldump")} #{arguments}"
289
+ end
290
+
291
+ def mysqlload(config_name, file_name)
292
+ mysql = self.class.new config_name
293
+ arg_port = mysql.db_port
294
+ arg_host = mysql.db_hostname
295
+ arg_user = mysql.DB_USER
296
+ arg_pass = mysql.DB_PASSWORD
297
+ arg_name = mysql.DB_NAME
298
+ arguments = "-P \"#{arg_port}\" -u \"#{arg_user}\" -h \"#{arg_host}\" -p\"#{arg_pass}\" -D \"#{arg_name}\""
299
+
300
+ "#{utility("mysql")} #{arguments} < #{file_name}"
40
301
  end
41
302
 
42
303
  end