wordpress-deploy 1.0.0.alpha1

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore ADDED
@@ -0,0 +1,2 @@
1
+ .DS_Store
2
+ pkg/*
data/Gemfile ADDED
@@ -0,0 +1,7 @@
1
+ # encoding: utf-8
2
+
3
+ # RubyGems Source
4
+ source 'http://rubygems.org'
5
+
6
+ # Include gem dependencies from the gemspec for development purposes
7
+ gemspec
data/Gemfile.lock ADDED
@@ -0,0 +1,71 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ wordpress-deploy (1.0.0)
5
+ actionpack (~> 3.2.6)
6
+ colorize (~> 0.5.8)
7
+ open4 (~> 1.3.0)
8
+ thor (~> 0.14.6)
9
+
10
+ GEM
11
+ remote: http://rubygems.org/
12
+ specs:
13
+ actionpack (3.2.6)
14
+ activemodel (= 3.2.6)
15
+ activesupport (= 3.2.6)
16
+ builder (~> 3.0.0)
17
+ erubis (~> 2.7.0)
18
+ journey (~> 1.0.1)
19
+ rack (~> 1.4.0)
20
+ rack-cache (~> 1.2)
21
+ rack-test (~> 0.6.1)
22
+ sprockets (~> 2.1.3)
23
+ activemodel (3.2.6)
24
+ activesupport (= 3.2.6)
25
+ builder (~> 3.0.0)
26
+ activesupport (3.2.6)
27
+ i18n (~> 0.6)
28
+ multi_json (~> 1.0)
29
+ builder (3.0.0)
30
+ colorize (0.5.8)
31
+ diff-lcs (1.1.3)
32
+ erubis (2.7.0)
33
+ hike (1.2.1)
34
+ i18n (0.6.0)
35
+ journey (1.0.4)
36
+ metaclass (0.0.1)
37
+ mocha (0.11.4)
38
+ metaclass (~> 0.0.1)
39
+ multi_json (1.3.6)
40
+ open4 (1.3.0)
41
+ rack (1.4.1)
42
+ rack-cache (1.2)
43
+ rack (>= 0.4)
44
+ rack-test (0.6.1)
45
+ rack (>= 1.0)
46
+ rake (0.9.2.2)
47
+ rspec (2.10.0)
48
+ rspec-core (~> 2.10.0)
49
+ rspec-expectations (~> 2.10.0)
50
+ rspec-mocks (~> 2.10.0)
51
+ rspec-core (2.10.1)
52
+ rspec-expectations (2.10.0)
53
+ diff-lcs (~> 1.1.3)
54
+ rspec-mocks (2.10.1)
55
+ sprockets (2.1.3)
56
+ hike (~> 1.2)
57
+ rack (~> 1.0)
58
+ tilt (~> 1.1, != 1.3.0)
59
+ thor (0.14.6)
60
+ tilt (1.3.3)
61
+ timecop (0.3.5)
62
+
63
+ PLATFORMS
64
+ ruby
65
+
66
+ DEPENDENCIES
67
+ mocha
68
+ rake
69
+ rspec
70
+ timecop
71
+ wordpress-deploy!
data/LICENSE.md ADDED
@@ -0,0 +1,24 @@
1
+
2
+ Copyright (c) 2012 Ryan Lovelett ( [@rlovelett](http://twitter.com/#!/rlovelett) )
3
+ =================================================================================================
4
+
5
+ The "Wordpress Deploy" RubyGem is released under the **MIT LICENSE**
6
+ ----------------------------------------------------------
7
+
8
+ Permission is hereby granted, free of charge, to any person obtaining a copy
9
+ of this software and associated documentation files (the "Software"), to deal
10
+ in the Software without restriction, including without limitation the rights
11
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12
+ copies of the Software, and to permit persons to whom the Software is
13
+ furnished to do so, subject to the following conditions:
14
+
15
+ The above copyright notice and this permission notice shall be included in
16
+ all copies or substantial portions of the Software.
17
+
18
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
24
+ THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,22 @@
1
+ Wordpress Deploy
2
+ ======
3
+
4
+ Wordpress Deploy is a RubyGem, written for Linux and Mac OSX, that allows you to easily perform Wordpress deployment operations. It provides you with an elegant DSL in Ruby for modeling your deployments.
5
+
6
+ ### Author
7
+
8
+ **[Ryan Lovelett](http://ryan.lovelett.me/) ( [@rlovelett](http://twitter.com/#!/rlovelett) )**
9
+
10
+ Drop me a message for any questions, suggestions, requests, bugs or submit them to the [issue log](https://github.com/rlovelett/wordpress-deploy/issues).
11
+
12
+
13
+ ### Installation
14
+
15
+ To get the latest stable version
16
+
17
+ gem install wordpress-deploy
18
+
19
+ You can view the list of released versions over at [RubyGems.org (Backup)](https://rubygems.org/gems/wordpress-deploy/versions)
20
+
21
+
22
+ ### Getting Started
data/Rakefile ADDED
@@ -0,0 +1,7 @@
1
+ #!/usr/bin/env rake
2
+ require "bundler/gem_tasks"
3
+ require "rspec/core/rake_task"
4
+
5
+ RSpec::Core::RakeTask.new(:spec)
6
+
7
+ task default: :spec
data/bin/wp-deploy ADDED
@@ -0,0 +1,11 @@
1
+ #!/usr/bin/env ruby
2
+ # encoding: utf-8
3
+
4
+ # Load the WordpressDeploy core library
5
+ require File.expand_path("../../lib/wordpress_deploy", __FILE__)
6
+
7
+ # Load the WordpressDeploy command line interface utility
8
+ require File.expand_path("../../lib/wordpress_deploy/cli/utility", __FILE__)
9
+
10
+ # Initialize the WordpressDeploy command line utility
11
+ WordpressDeploy::CLI::Utility.start
@@ -0,0 +1,91 @@
1
+ # encoding: utf-8
2
+
3
+ module WordpressDeploy
4
+ module CLI
5
+ module Helpers
6
+ UTILITY = {}
7
+
8
+ ##
9
+ # Runs a system command
10
+ #
11
+ # All messages generated by the command will be logged.
12
+ # Messages on STDERR will be logged as warnings.
13
+ #
14
+ # If the command fails to execute, or returns a non-zero exit status
15
+ # an Error will be raised.
16
+ #
17
+ # Returns nil
18
+ def run(command)
19
+ name = command_name(command)
20
+ Logger.message "Running system utility '#{ name }'..."
21
+
22
+ begin
23
+ out, err = '', ''
24
+ ps = Open4.popen4(command) do |pid, stdin, stdout, stderr|
25
+ stdin.close
26
+ out, err = stdout.read.strip, stderr.read.strip
27
+ end
28
+ rescue Exception => e
29
+ raise Errors::CLI::SystemCallError.wrap(e, <<-EOS)
30
+ Failed to execute system command on #{ RUBY_PLATFORM }
31
+ Command was: #{ command }
32
+ EOS
33
+ end
34
+
35
+ if ps.success?
36
+ unless out.empty?
37
+ Logger.message(
38
+ out.lines.map {|line| "#{ name }:STDOUT: #{ line }" }.join
39
+ )
40
+ end
41
+
42
+ unless err.empty?
43
+ Logger.warn(
44
+ err.lines.map {|line| "#{ name }:STDERR: #{ line }" }.join
45
+ )
46
+ end
47
+
48
+ return nil
49
+ else
50
+ raise Errors::CLI::SystemCallError, <<-EOS
51
+ '#{ name }' Failed on #{ RUBY_PLATFORM }
52
+ The following information should help to determine the problem:
53
+ Command was: #{ command }
54
+ Exit Status: #{ ps.exitstatus }
55
+ STDOUT Messages: #{ out.empty? ? 'None' : "\n#{ out }" }
56
+ STDERR Messages: #{ err.empty? ? 'None' : "\n#{ err }" }
57
+ EOS
58
+ end
59
+ end
60
+
61
+
62
+ ##
63
+ # Returns the full path to the specified utility.
64
+ # Raises an error if utility can not be found in the system's $PATH
65
+ def utility(name)
66
+ name = name.to_s.strip
67
+ raise Errors::CLI::UtilityNotFoundError,
68
+ 'Utility Name Empty' if name.empty?
69
+
70
+ path = UTILITY[name] || %x[which #{ name } 2>/dev/null].chomp
71
+ if path.empty?
72
+ raise Errors::CLI::UtilityNotFoundError, <<-EOS
73
+ Could not locate '#{ name }'.
74
+ Make sure the specified utility is installed
75
+ and available in your system's $PATH.
76
+ EOS
77
+ end
78
+ UTILITY[name] = path
79
+ end
80
+
81
+ ##
82
+ # Returns the name of the command name from the given command line
83
+ def command_name(command)
84
+ i = command =~ /\s/
85
+ command = command.slice(0, i) if i
86
+ command.split('/')[-1]
87
+ end
88
+
89
+ end
90
+ end
91
+ end
@@ -0,0 +1,53 @@
1
+ # encoding: utf-8
2
+
3
+ ##
4
+ # Build the WordpressDeploy Command Line Interface using Thor
5
+ module WordpressDeploy
6
+ module CLI
7
+ class Utility < Thor
8
+ include Thor::Actions
9
+
10
+ method_option :base, type: :string, aliases: ['-b']
11
+ method_option :env, type: :string, required: true, default: 'production', aliases: ['-e']
12
+ desc "generate", "Generate the wp-config.php file. Accepted environments are production or development."
13
+ 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
45
+
46
+
47
+ desc "deploy", "Deploy #{Config.sites_dir} via FTP to #{Config.ftp_config['hostname']}"
48
+ def deploy
49
+
50
+ end
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,68 @@
1
+ # encoding: utf-8
2
+
3
+ module WordpressDeploy
4
+ module Config
5
+ DEFAULTS = {
6
+ :config_file => 'config.rb',
7
+ :data_path => 'data',
8
+ :log_path => 'log',
9
+ :cache_path => '.cache',
10
+ :tmp_path => '.tmp'
11
+ }
12
+
13
+ class << self
14
+ # These paths are the basis for all scripts
15
+ attr_reader :base_dir
16
+ def base_dir
17
+ @base_dir ||= Dir.pwd
18
+ end
19
+ attr_reader :config_dir
20
+ def config_dir
21
+ @config_dir ||= File.join(base_dir, "config")
22
+ end
23
+ attr_reader :sites_dir
24
+ def sites_dir
25
+ @sites_dir ||= File.join(base_dir, "site")
26
+ end
27
+
28
+ attr_reader :ftp_config
29
+ def ftp_config
30
+ @ftp_config ||= YAML.load_file(File.join(config_dir, "ftp.yml"))
31
+ end
32
+
33
+ attr_reader :wp_config
34
+ def wp_config
35
+ @wp_config ||= YAML.load_file(File.join(config_dir, "wp-config.yml"))
36
+ end
37
+
38
+ attr_reader :wp_config_sample
39
+ def wp_config_sample
40
+ @wp_config_sample ||= File.join(sites_dir, "wp-config-sample.php")
41
+ end
42
+ attr_reader :wp_config_output
43
+ def wp_config_output
44
+ @wp_config_output ||= File.join(sites_dir, "wp-config.php")
45
+ end
46
+
47
+ attr_reader :environment
48
+ def environment
49
+ @environment ||= "production"
50
+ end
51
+ alias :env :environment
52
+
53
+ def environment=(new_env)
54
+ @environment = new_env.downcase
55
+ end
56
+
57
+ # The Salting array
58
+ def salt_array
59
+ @salt_array ||= %w{0 1 2 3 4 5 6 7 8 9 a b c d e f g h i j k l m n o p q r s t u v w x y z A B C D E F G H I J K L M N O P Q R S T U V W X Y Z ! @ # $ % ^ & * ( ) - ~ + = | / { } : ; , . ? < > [ ]}
60
+ end
61
+
62
+ def salt_keys
63
+ @salt_keys ||= %w{AUTH_KEY SECURE_AUTH_KEY LOGGED_IN_KEY NONCE_KEY AUTH_SALT SECURE_AUTH_SALT LOGGED_IN_SALT NONCE_SALT}
64
+ end
65
+
66
+ end
67
+ end
68
+ end
@@ -0,0 +1,53 @@
1
+ # encoding: utf-8
2
+
3
+ module WordpressDeploy
4
+ module Database
5
+ class Base
6
+ include WordpressDeploy::CLI::Helpers
7
+ include WordpressDeploy::Configuration::Helpers
8
+
9
+ ##
10
+ # Creates a new instance of the MongoDB database object
11
+ # * Called using super(model) from subclasses *
12
+ def initialize(model)
13
+ @model = model
14
+ load_defaults!
15
+ end
16
+
17
+ ##
18
+ # Super method for all child (database) objects. Every database object's #perform!
19
+ # method should call #super before anything else to prepare
20
+ def perform!
21
+ prepare!
22
+ log!
23
+ end
24
+
25
+ private
26
+
27
+ ##
28
+ # Defines the @dump_path and ensures it exists by creating it
29
+ def prepare!
30
+ @dump_path = File.join(
31
+ Config.tmp_path,
32
+ @model.trigger,
33
+ 'databases',
34
+ self.class.name.split('::').last
35
+ )
36
+ FileUtils.mkdir_p(@dump_path)
37
+ end
38
+
39
+ ##
40
+ # Return the database name, with WordpressDeploy namespace removed
41
+ def database_name
42
+ self.class.to_s.sub('WordpressDeploy::', '')
43
+ end
44
+
45
+ ##
46
+ # Logs a message to the console and log file to inform
47
+ # the client that WordpressDeploy is dumping the database
48
+ def log!
49
+ Logger.message "#{ database_name } started dumping and archiving '#{ name }'."
50
+ end
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,159 @@
1
+ # encoding: utf-8
2
+
3
+ module WordpressDeploy
4
+ module Database
5
+ class MySQL < Base
6
+
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
31
+
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?
49
+
50
+ @name ||= :all
51
+ @mysqldump_utility ||= utility(:mysqldump)
52
+ end
53
+
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
+ def mysqldump
87
+ "#{ mysqldump_utility } #{ credential_options } #{ connectivity_options } " +
88
+ "#{ user_options } #{ db_name } #{ tables_to_dump } #{ tables_to_skip }"
89
+ end
90
+
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(' ')
115
+ end
116
+
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
131
+
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
138
+
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(' ')
147
+ end
148
+
149
+ ##
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
155
+ end
156
+
157
+ end
158
+ end
159
+ end
@@ -0,0 +1,70 @@
1
+ # encoding: utf-8
2
+
3
+ module WordpressDeploy
4
+ module Errors
5
+
6
+ class Error < StandardError
7
+
8
+ def self.wrap(orig_err, msg = nil)
9
+ new(msg, orig_err)
10
+ end
11
+
12
+ def initialize(msg = nil, orig_err = nil)
13
+ super(msg)
14
+ set_backtrace(orig_err.backtrace) if @orig_err = orig_err
15
+ end
16
+
17
+ def to_s
18
+ return @to_s if @to_s
19
+ orig_to_s = super()
20
+
21
+ if orig_to_s == self.class.to_s
22
+ msg = orig_err_msg ?
23
+ "#{orig_err_class}: #{orig_err_msg}" : orig_err_class
24
+ else
25
+ msg = format_msg(orig_to_s)
26
+ msg << "\n Reason: #{orig_err_class}" + (orig_err_msg ?
27
+ "\n #{orig_err_msg}" : ' (no message given)') if @orig_err
28
+ end
29
+
30
+ @to_s = msg ? msg_prefix + msg : class_name
31
+ end
32
+
33
+ private
34
+
35
+ def msg_prefix
36
+ @msg_prefix ||= class_name + ': '
37
+ end
38
+
39
+ def orig_msg
40
+ @orig_msg ||= to_s.sub(msg_prefix, '')
41
+ end
42
+
43
+ def class_name
44
+ @class_name ||= self.class.to_s.sub('WordpressDeploy::Errors::', '')
45
+ end
46
+
47
+ def orig_err_class
48
+ return unless @orig_err
49
+
50
+ @orig_err_class ||= @orig_err.is_a?(Errors::Error) ?
51
+ @orig_err.send(:class_name) : @orig_err.class.to_s
52
+ end
53
+
54
+ def orig_err_msg
55
+ return unless @orig_err
56
+ return @orig_err_msg unless @orig_err_msg.nil?
57
+
58
+ msg = @orig_err.is_a?(Errors::Error) ?
59
+ @orig_err.send(:orig_msg) : @orig_err.to_s
60
+ @orig_err_msg = (msg == orig_err_class) ?
61
+ false : format_msg(msg)
62
+ end
63
+
64
+ def format_msg(msg)
65
+ msg.gsub(/^ */, ' ').strip
66
+ end
67
+ end
68
+
69
+ end
70
+ end