wordpress-deploy 1.0.0.alpha2 → 1.0.0.rc1

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.
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