wordpress-deploy 1.0.0.alpha1 → 1.0.0.alpha2

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 (38) hide show
  1. data/.gitignore +26 -1
  2. data/.rspec +1 -0
  3. data/.rvmrc +48 -0
  4. data/.travis.yml +4 -0
  5. data/Gemfile +2 -5
  6. data/Gemfile.lock +40 -28
  7. data/Guardfile +24 -0
  8. data/README.md +22 -7
  9. data/bin/wp-deploy +1 -4
  10. data/lib/wordpress_deploy.rb +22 -48
  11. data/lib/wordpress_deploy/cli/helpers.rb +27 -14
  12. data/lib/wordpress_deploy/cli/utility.rb +86 -37
  13. data/lib/wordpress_deploy/database/mysql.rb +22 -136
  14. data/lib/wordpress_deploy/environment.rb +68 -0
  15. data/lib/wordpress_deploy/errors.rb +54 -0
  16. data/lib/wordpress_deploy/logger.rb +28 -50
  17. data/lib/wordpress_deploy/transfer_protocols/ftp.rb +305 -0
  18. data/lib/wordpress_deploy/version.rb +1 -1
  19. data/lib/wordpress_deploy/wordpress/configuration.rb +196 -0
  20. data/spec/data/ftp.yml +4 -0
  21. data/spec/data/wp-config-sample.php +90 -0
  22. data/spec/data/wp-config.yml +128 -0
  23. data/spec/database/mysql_spec.rb +93 -0
  24. data/spec/environment_spec.rb +35 -0
  25. data/spec/spec_helper.rb +36 -1
  26. data/spec/transfer_protocols/ftp_spec.rb +193 -0
  27. data/spec/wordpress/configuration_spec.rb +202 -0
  28. data/wordpress_deploy.gemspec +13 -10
  29. metadata +63 -47
  30. data/lib/wordpress_deploy/config.rb +0 -68
  31. data/lib/wordpress_deploy/database/base.rb +0 -53
  32. data/lib/wordpress_deploy/pipeline.rb +0 -110
  33. data/lib/wordpress_deploy/storage/base.rb +0 -99
  34. data/lib/wordpress_deploy/storage/ftp.rb +0 -133
  35. data/lib/wordpress_deploy/storage/local.rb +0 -82
  36. data/lib/wordpress_deploy/storage/scp.rb +0 -99
  37. data/lib/wordpress_deploy/storage/sftp.rb +0 -108
  38. data/spec/config_spec.rb +0 -16
@@ -1,53 +1,102 @@
1
- # encoding: utf-8
2
-
3
1
  ##
4
2
  # Build the WordpressDeploy Command Line Interface using Thor
3
+ #
5
4
  module WordpressDeploy
6
- module CLI
5
+ module Cli
7
6
  class Utility < Thor
8
7
  include Thor::Actions
9
8
 
10
- method_option :base, type: :string, aliases: ['-b']
11
- method_option :env, type: :string, required: true, default: 'production', aliases: ['-e']
9
+ # These options apply to all commands
10
+ class_option :root_dir, type: :string, default: '', aliases: '-r'
11
+ class_option :wp_dir, type: :string, default: '', aliases: '-w'
12
+ class_option :environment, type: :string, default: 'production', aliases: '-e'
13
+ class_option :verbose, type: :boolean, default: false, aliases: '-v'
14
+
15
+
12
16
  desc "generate", "Generate the wp-config.php file. Accepted environments are production or development."
13
17
  def generate
14
- unless %w{production development}.include? options[:env]
15
- raise Errors::CLI::SystemCallError.wrap(e, <<-EOS)
16
- Failed to execute system command on #{ RUBY_PLATFORM }
17
- Command was: #{ command }
18
- EOS
19
- end
20
-
21
- Config.environment = options[:env]
22
- config = Config.wp_config[Config.env]
23
-
24
- # Salt the wp-config.php file if none are provided
25
- Config.salt_keys.each do |key|
26
- config[key] = Config.salt_array.sample(64).join("") unless config.has_key? key
27
- end
28
-
29
- out = File.open(Config.wp_config_output, 'w')
30
- File.open(Config.wp_config_sample, 'r') do |file|
31
- file.each_line do |line|
32
- match = /^define\(['"](?<parameter>\w*)['"]/.match(line)
33
- unless match.nil?
34
- param = match[:parameter]
35
- if config.has_key?(param)
36
- # The Wordpress Config file has the key
37
- # So now set the value from the config
38
- line.gsub!(/['"]((?!#{param})[\s\w\d\!\@\#\$\%\^\&\*\-\(\)]+)?['"]/, "'#{config[param]}'")
39
- end
40
- end
41
- out.puts(line)
42
- end
43
- end
44
- end
18
+ ##
19
+ # Set Logger into verbose mode (if the user requested it)
20
+ Logger.verbose = options[:verbose]
21
+
22
+ # Set environment options
23
+ Environment.set_options options
24
+
25
+ # Create a configuration file
26
+ config = Wordpress::Configuration.new
45
27
 
28
+ # Save the configuration file
29
+ config.save!
30
+ rescue => err
31
+ Logger.error Errors::Cli::Utility::Error.wrap(err)
46
32
 
47
- desc "deploy", "Deploy #{Config.sites_dir} via FTP to #{Config.ftp_config['hostname']}"
33
+ # Exit with an error
34
+ exit(1)
35
+ end
36
+
37
+ desc "deploy", "Deploy via FTP to configuration hostname."
48
38
  def deploy
39
+ ##
40
+ # Set Logger into verbose mode (if the user requested it)
41
+ Logger.verbose = options[:verbose]
42
+
43
+ # Set environment options
44
+ Environment.set_options options
45
+
46
+ # Create a new FTP client for sending the files
47
+ ftp_client = TransferProtocols::Ftp.new options[:environment]
48
+
49
+ # Now transmit the files
50
+ ftp_client.transmit!
51
+
52
+ rescue => err
53
+ Logger.error Errors::Cli::Utility::Error.wrap(err)
49
54
 
55
+ # Exit with an error
56
+ exit(1)
57
+ ensure
58
+ puts "Closing connection.".colorize(color: :red, background: :yellow) if ftp_client.close
59
+ end
60
+
61
+ desc "backup", "Pull down the remote files over FTP."
62
+ def backup
63
+ ##
64
+ # Set Logger into verbose mode (if the user requested it)
65
+ Logger.verbose = options[:verbose]
66
+
67
+ # Set environment options
68
+ Environment.set_options options
69
+
70
+ # Create a new FTP client for receiving the files
71
+ ftp_client = TransferProtocols::Ftp.new options[:environment]
72
+
73
+ # Now receive the files
74
+ ftp_client.receive!
75
+
76
+ rescue => err
77
+ Logger.error Errors::Cli::Utility::Error.wrap(err)
78
+
79
+ # Exit with an error
80
+ exit(1)
81
+ ensure
82
+ puts "Closing connection.".colorize(color: :red, background: :yellow) if ftp_client.close
83
+ end
84
+
85
+ desc "mirror", "Mirror database between two locations"
86
+ def mirror(from, to)
87
+ ##
88
+ # Set Logger into verbose mode (if the user requested it)
89
+ Logger.verbose = options[:verbose]
90
+
91
+ # Set environment options
92
+ Environment.set_options options
93
+ rescue => err
94
+ Logger.error Errors::Cli::Utility::Error.wrap(err)
95
+
96
+ # Exit with an error
97
+ exit(1)
50
98
  end
51
99
  end
52
100
  end
53
101
  end
102
+
@@ -1,159 +1,45 @@
1
- # encoding: utf-8
1
+ require 'tmpdir'
2
2
 
3
3
  module WordpressDeploy
4
4
  module Database
5
- class MySQL < Base
6
5
 
7
- ##
8
- # Name of the database that needs to get dumped
9
- # To dump all databases, set this to `:all` or leave blank.
10
- attr_accessor :name
11
-
12
- ##
13
- # Credentials for the specified database
14
- attr_accessor :username, :password
15
-
16
- ##
17
- # Connectivity options
18
- attr_accessor :host, :port, :socket
19
-
20
- ##
21
- # Tables to skip while dumping the database
22
- attr_accessor :skip_tables
23
-
24
- ##
25
- # Tables to dump, tables that aren't specified won't get dumped
26
- attr_accessor :only_tables
27
-
28
- ##
29
- # Additional "mysqldump" options
30
- attr_accessor :additional_options
6
+ class MySql
7
+ include WordpressDeploy::Cli::Helpers
31
8
 
32
- ##
33
- # Path to mysqldump utility (optional)
34
- attr_accessor :mysqldump_utility
35
-
36
- attr_deprecate :utility_path, :version => '3.0.21',
37
- :replacement => :mysqldump_utility
38
-
39
- ##
40
- # Creates a new instance of the MySQL adapter object
41
- def initialize(model, &block)
42
- super(model)
43
-
44
- @skip_tables ||= Array.new
45
- @only_tables ||= Array.new
46
- @additional_options ||= Array.new
47
-
48
- instance_eval(&block) if block_given?
9
+ attr_reader :configuration
49
10
 
50
- @name ||= :all
51
- @mysqldump_utility ||= utility(:mysqldump)
11
+ def initialize
12
+ @yaml = YAML.load_file(File.join(Environment.config_dir, "wp-config.yml"))
52
13
  end
53
14
 
54
- ##
55
- # Performs the mysqldump command and outputs the
56
- # data to the specified path based on the 'trigger'
57
- def perform!
58
- super
59
-
60
- pipeline = Pipeline.new
61
- dump_ext = 'sql'
62
-
63
- pipeline << mysqldump
64
- if @model.compressor
65
- @model.compressor.compress_with do |command, ext|
66
- pipeline << command
67
- dump_ext << ext
68
- end
69
- end
70
- pipeline << "cat > '#{ File.join(@dump_path, dump_filename) }.#{ dump_ext }'"
71
-
72
- pipeline.run
73
- if pipeline.success?
74
- Logger.message "#{ database_name } Complete!"
75
- else
76
- raise Errors::Database::PipelineError,
77
- "#{ database_name } Dump Failed!\n" +
78
- pipeline.error_messages
79
- end
80
- end
81
-
82
- private
83
-
84
- ##
85
- # Builds the full mysqldump string based on all attributes
86
15
  def mysqldump
87
- "#{ mysqldump_utility } #{ credential_options } #{ connectivity_options } " +
88
- "#{ user_options } #{ db_name } #{ tables_to_dump } #{ tables_to_skip }"
16
+ "#{utility("mysqldump")} #{arguments}"
89
17
  end
90
18
 
91
- ##
92
- # Returns the filename to use for dumping the database(s)
93
- def dump_filename
94
- dump_all? ? 'all-databases' : name
95
- end
96
-
97
- ##
98
- # Builds the credentials MySQL syntax to authenticate the user
99
- # to perform the database dumping process
100
- def credential_options
101
- %w[username password].map do |option|
102
- next if send(option).to_s.empty?
103
- "--#{option}='#{send(option)}'".gsub('--username', '--user')
104
- end.compact.join(' ')
105
- end
106
-
107
- ##
108
- # Builds the MySQL connectivity options syntax to connect the user
109
- # to perform the database dumping process
110
- def connectivity_options
111
- %w[host port socket].map do |option|
112
- next if send(option).to_s.empty?
113
- "--#{option}='#{send(option)}'"
114
- end.compact.join(' ')
19
+ def configuration=(new_config)
20
+ @configuration = new_config if new_config.instance_of? WordpressDeploy::Wordpress::Configuration
115
21
  end
116
22
 
117
- ##
118
- # Builds a MySQL compatible string for the additional options
119
- # specified by the user
120
- def user_options
121
- additional_options.join(' ')
122
- end
123
-
124
- ##
125
- # Returns the database name to use in the mysqldump command.
126
- # When dumping all databases, the database name is replaced
127
- # with the command option to dump all databases.
128
- def db_name
129
- dump_all? ? '--all-databases' : name
130
- end
23
+ private
131
24
 
132
- ##
133
- # Builds the MySQL syntax for specifying which tables to dump
134
- # during the dumping of the database
135
- def tables_to_dump
136
- only_tables.join(' ') unless dump_all?
137
- end
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
138
31
 
139
- ##
140
- # Builds the MySQL syntax for specifying which tables to skip
141
- # during the dumping of the database
142
- def tables_to_skip
143
- skip_tables.map do |table|
144
- table = (dump_all? || table['.']) ? table : "#{ name }.#{ table }"
145
- "--ignore-table='#{ table }'"
146
- end.join(' ')
32
+ "-P \"#{port}\" -h \"#{host}\" -u \"#{username}\" -p#{password} -B \"#{db_name}\""
147
33
  end
148
34
 
149
35
  ##
150
- # Return true if we're dumping all databases.
151
- # `name` will be set to :all if it is not set,
152
- # so this will be true by default
153
- def dump_all?
154
- name == :all
36
+ # A temporary directory for installing the executable to
37
+ def tmp_dir
38
+ @tmp_dir ||= Dir.mktmpdir
39
+ File.expand_path(@tmp_dir)
155
40
  end
156
41
 
157
42
  end
158
43
  end
159
44
  end
45
+
@@ -0,0 +1,68 @@
1
+ module WordpressDeploy
2
+ ##
3
+ # Environment 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 Environment
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.log_file
60
+ @@log_file ||= "#{Time.now.strftime("%Y_%m_%d_%H_%M_%S")}.log"
61
+ File.expand_path File.join(root_dir, @@log_file)
62
+ end
63
+
64
+ def self.clean!
65
+ FileUtils.rm Dir.glob(File.join(root_dir, "*.log"))
66
+ end
67
+ end
68
+ end
@@ -1,7 +1,61 @@
1
1
  # encoding: utf-8
2
2
 
3
3
  module WordpressDeploy
4
+ ##
5
+ # - automatically defines module namespaces referenced under WordpressDeploy::Errors
6
+ # - any constant name referenced that ends with 'Error' will be created
7
+ # as a subclass of WordpressDeploy::Errors::Error
8
+ # e.g.
9
+ # err = WordpressDeploy::Errors::Foo::Bar::FooError.new('error message')
10
+ # err.message => "Foo::Bar::FooError: error message"
11
+ #
12
+ module ErrorsHelper
13
+ def const_missing(const)
14
+ if const.to_s.end_with?('Error')
15
+ module_eval("class #{const} < WordpressDeploy::Errors::Error; end")
16
+ else
17
+ module_eval("module #{const}; extend WordpressDeploy::ErrorsHelper; end")
18
+ end
19
+ const_get(const)
20
+ end
21
+ end
22
+
23
+ ##
24
+ # provides cascading errors with formatted messages
25
+ # see the specs for details
26
+ #
27
+ # e.g.
28
+ # module WordpressDeploy
29
+ # begin
30
+ # begin
31
+ # begin
32
+ # raise Errors::ZoneAError, 'an error occurred in Zone A'
33
+ # rescue => err
34
+ # raise Errors::ZoneBError.wrap(err, <<-EOS)
35
+ # an error occurred in Zone B
36
+ #
37
+ # the following error should give a reason
38
+ # EOS
39
+ # end
40
+ # rescue => err
41
+ # raise Errors::ZoneCError.wrap(err)
42
+ # end
43
+ # rescue => err
44
+ # puts Errors::ZoneDError.wrap(err, 'an error occurred in Zone D')
45
+ # end
46
+ # end
47
+ #
48
+ # Outputs:
49
+ # ZoneDError: an error occurred in Zone D
50
+ # Reason: ZoneCError
51
+ # ZoneBError: an error occurred in Zone B
52
+ #
53
+ # the following error should give a reason
54
+ # Reason: ZoneAError
55
+ # an error occurred in Zone A
56
+ #
4
57
  module Errors
58
+ extend ErrorsHelper
5
59
 
6
60
  class Error < StandardError
7
61