capistrano-extensions 0.1.5 → 0.1.8

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.
@@ -0,0 +1,10 @@
1
+ Known Bugs and Shortcomings
2
+
3
+ (this one is specific to passenger-recipes, which really should be merged into capistrano-extensions...)
4
+ * When introducing a new shared content directory, a bug can manifest itself when trying to sync production data back to your staging server. Consider the following scenario:
5
+ 1) Add a new upload field to your app (e.g. using file_column)
6
+ 2) Update the deploy script to reference this new shared directory (via either :shared_content or :content_directories)
7
+ 3) Try cap remote:sync FROM=production TO=staging --> It will fail when it tries to tarball up the shared content on production.
8
+
9
+ Currently, the best workaround is to log onto your production server and created the shared content directory, e.g. #{shared_path}/content/model_that_you_added_file_column_to
10
+
@@ -1,11 +1,15 @@
1
1
  History.txt
2
+ ISSUES.txt
2
3
  Manifest.txt
3
4
  README.txt
4
5
  Rakefile
6
+ TODO
5
7
  bin/capistrano-extensions-sync-content
6
8
  bin/capistrano-extensions-sync-db
7
9
  capistrano-extensions.gemspec
8
10
  lib/capistrano-extensions.rb
9
11
  lib/capistrano-extensions/deploy.rb
10
12
  lib/capistrano-extensions/geminstaller_dependency.rb
13
+ lib/capistrano-extensions/recipes/content_sync.rb
14
+ lib/capistrano-extensions/recipes/db_sync.rb
11
15
  lib/capistrano-extensions/version.rb
@@ -0,0 +1,32 @@
1
+ = capistrano-extensions
2
+
3
+ * Stable API: http://johntrupiano.rubyforge.org/capistrano-extensions
4
+ * Source: http://github.com/jtrupiano/capistrano-extensions
5
+
6
+ == DESCRIPTION/FEATURES:
7
+
8
+ This gem provides a base set of {Capistrano}[http://www.capify.org/] extensions including the following:
9
+ * a new :gemfile RemoteDependency type
10
+ * tasks/helpers for handling public and private asset folders (e.g. created by the file_column plugin)
11
+ * tasks/helpers for auto-syncing server gems (via integration with the {GemInstaller}[http://geminstaller.rubyforge.org/] gem)
12
+ * helpers for dealing with multiple deployable environments (e.g. staging, prodtest, production)
13
+ * tasks for working with remote logfiles
14
+ * tasks for database/asset synchronization from production back to local environments
15
+ * integration with {environmentalist}[http://johntrupiano.rubyforge.org/environmentalist]
16
+
17
+ For a detailed exploration of these features, check out the wiki: http://github.com/jtrupiano/capistrano-extensions/wikis/home
18
+
19
+ == SYNOPSIS:
20
+
21
+ FIX (code sample of usage)
22
+
23
+ == REQUIREMENTS:
24
+
25
+ * Capistrano ~> 2.5.5
26
+ * GemInstaller ~> 0.5.1
27
+
28
+ == INSTALL:
29
+
30
+ * sudo gem install capistrano-extensions (stable from rubyforge)
31
+ * sudo gem install jtrupiano-capistrano-extensions (HEAD of repo from github)
32
+
@@ -0,0 +1,4 @@
1
+ ---
2
+ :major: 0
3
+ :minor: 1
4
+ :patch: 8
@@ -1,9 +1,8 @@
1
1
  require 'capistrano-extensions/geminstaller_dependency'
2
- require 'capistrano/server_definition'
3
2
 
4
3
  # Overrides the majority of recipes from Capistrano's deploy recipe set.
5
4
  Capistrano::Configuration.instance(:must_exist).load do
6
- # Add sls_recipes to the load path
5
+ # Add us to the load path
7
6
  @load_paths << File.expand_path(File.dirname(__FILE__))
8
7
 
9
8
  # ========================================================================
@@ -27,10 +26,10 @@ Capistrano::Configuration.instance(:must_exist).load do
27
26
  # changes if you do decide to muck with these!
28
27
  # =========================================================================
29
28
 
30
- set(:use_sudo, false) # we don't want to use sudo-- we don't have to!
31
- set(:deploy_via, :export) # we don't want our .svn folders on the server!
32
- _cset(:deploy_to) { "/var/www/vhosts/#{application}" }
33
- _cset(:deployable_environments, [:production])
29
+ set(:use_sudo, false) # we don't want to use sudo-- we don't have to!
30
+ set(:deploy_via, :copy) # no need to have subversion on the production server
31
+ _cset(:deploy_to) { "/var/vhosts/#{application}" }
32
+ _cset(:deployable_environments, [:staging])
34
33
 
35
34
  _cset(:rails_config_path) { File.join(latest_release, 'config') }
36
35
  _cset(:db_conf) {
@@ -45,11 +44,36 @@ Capistrano::Configuration.instance(:must_exist).load do
45
44
  _cset(:public_path) { File.join(latest_release, 'public') }
46
45
  _cset(:log_path) { "/var/log/#{application}" }
47
46
 
47
+ # Local Properties
48
+ _cset(:tmp_dir, "tmp/cap")
49
+ # when local:syncing, should we keep backups just in case of failure?
50
+ _cset(:store_dev_backups, false)
51
+ # how long to allow remote backups to be valid (at both cache levels)
52
+ _cset(:remote_backup_expires, 172800) # 2 days in seconds.
53
+ # when remote:syncing, should we keep backups just in case of failure?
54
+ _cset(:store_remote_backups, true)
55
+ # paths to exclude during deployment
56
+ _cset(:exclude_paths, [])
57
+
58
+ _cset(:copy_cache) { File.expand_path("~/.capistrano/#{application}") }
59
+ set(:copy_exclude) {
60
+ # don't deploy the other environment directories
61
+ envs = fetch(:deployable_environments).dup
62
+ envs.delete_if { |env| rails_env.to_sym == env.to_sym }
63
+ envs.map! { |env| File.join("config", "#{env}") }
64
+
65
+ envs + fetch(:exclude_paths)
66
+ }
67
+
68
+ _cset(:zip, "gzip")
69
+ _cset(:unzip, "gunzip")
70
+ _cset(:zip_ext, "gz")
71
+
48
72
  # Allow recipes to ask for a certain local environment
49
73
  def local_db_conf(env = nil)
50
74
  env ||= fetch(:rails_env)
51
75
  fetch(:config_structure, :rails).to_sym == :sls ?
52
- File.join('config', env, 'database.yml') :
76
+ File.join('config', env.to_s, 'database.yml') :
53
77
  File.join('config', 'database.yml')
54
78
  end
55
79
 
@@ -79,17 +103,16 @@ Capistrano::Configuration.instance(:must_exist).load do
79
103
  # Now, let's actually include our common recipes!
80
104
  namespace :deploy do
81
105
  desc <<-DESC
82
- [capistrano-extensions] Creates shared directories and symbolic links to them by the
83
- :content_directories and :shared_content properties. See the README for
84
- further explanation.
106
+ [capistrano-extensions] Creates shared directories and symbolic links to them by reading the
107
+ :content_directories and :shared_content properties. See the README for further explanation.
85
108
  DESC
86
109
  task :create_shared_file_column_dirs, :roles => :app, :except => { :no_release => true } do
87
110
  mappings = content_directories.inject(shared_content) { |hsh, dir| hsh.merge({"content/#{dir}" => "public/#{dir}"}) }
88
111
  mappings.each_pair do |remote, local|
89
112
  run <<-CMD
113
+ umask 0022 &&
90
114
  mkdir -p #{shared_path}/#{remote} &&
91
- ln -sf #{shared_path}/#{remote} #{latest_release}/#{local} &&
92
- chmod 755 -R #{shared_path}/#{remote}
115
+ ln -sf #{shared_path}/#{remote} #{latest_release}/#{local}
93
116
  CMD
94
117
  end
95
118
  end
@@ -115,88 +138,17 @@ Capistrano::Configuration.instance(:must_exist).load do
115
138
  filesystem
116
139
  DESC
117
140
  task :pull do
118
- tmp_location = "#{shared_path}/#{rails_env}.log.gz"
119
- run "cp #{log_path}/#{rails_env}.log #{shared_path}/ && gzip #{shared_path}/#{rails_env}.log"
120
- get "#{tmp_location}", "#{application}-#{rails_env}.log.gz"
141
+ tmp_location = "#{shared_path}/#{rails_env}.log.#{zip_ext}"
142
+ run "cp #{log_path}/#{rails_env}.log #{shared_path}/ && #{zip} #{shared_path}/#{rails_env}.log"
143
+ get "#{tmp_location}", "#{application}-#{rails_env}.log.#{zip_ext}"
121
144
  run "rm #{tmp_location}"
122
145
  end
123
146
  end
124
147
 
148
+ load 'recipes/db_sync'
149
+ load 'recipes/content_sync'
150
+
125
151
  namespace :remote do
126
- desc <<-DESC
127
- [capistrano-extensions] Uploads the backup file downloaded from local:backup_db (specified via the FROM env variable),
128
- copies it to the remove environment specified by RAILS_ENV, and imports (via mysql command line tool) it back into the
129
- remote database.
130
- DESC
131
- task :restore_db, :roles => :db do
132
- env = ENV['FROM'] || 'production'
133
-
134
- puts "\033[1;41m Restoring database backup to #{rails_env} environment \033[0m"
135
- if deployable_environments.include?(rails_env.to_sym)
136
- # remote environment
137
- local_backup_file = "#{application}-#{env}-db.sql.gz"
138
- remote_file = "#{shared_path}/restore_db.sql"
139
- if !File.exists?(local_backup_file)
140
- puts "Could not find backup file: #{local_backup_file}"
141
- exit 1
142
- end
143
- upload(local_backup_file, "#{remote_file}.gz")
144
-
145
- pass_str = pluck_pass_str(db)
146
- run "gunzip -f #{remote_file}.gz"
147
- run "mysql -u#{db['username']} #{pass_str} #{db['database']} < #{remote_file}"
148
- run "rm -f #{remote_file}"
149
- end
150
- end
151
-
152
- desc <<-DESC
153
- [capistrano-extensions]: Backs up target deployable environment's database (identified
154
- by the FROM environment variable, which defaults to 'production') and restores it to
155
- the remote database identified by the TO environment variable, which defaults to "staging."
156
- DESC
157
- task :sync_db do
158
- system("capistrano-extensions-sync-db #{ENV['FROM'] || 'production'} #{ENV['TO'] || 'staging'}")
159
- end
160
-
161
- desc <<-DESC
162
- [capistrano-extensions]: Uploads the backup file downloaded from local:backup_content (specified via the
163
- FROM env variable), copies it to the remote environment specified by RAILS_ENV, and unpacks it into the
164
- shared/ directory.
165
- DESC
166
- task :restore_content do
167
- from = ENV['FROM'] || 'production'
168
-
169
- if deployable_environments.include?(rails_env.to_sym)
170
- local_backup_file = "#{application}-#{from}-content_backup.tar.gz"
171
- remote_file = "#{shared_path}/content_backup.tar.gz"
172
-
173
- if !File.exists?(local_backup_file)
174
- puts "Could not find backup file: #{local_backup_file}"
175
- exit 1
176
- end
177
-
178
- upload(local_backup_file, "#{remote_file}")
179
- remote_dirs = ["content"] + shared_content.keys
180
-
181
- run("cd #{shared_path} && rm -rf #{remote_dirs.join(' ')} && tar xzf #{remote_file} -C #{shared_path}/")
182
- end
183
- end
184
-
185
- desc <<-DESC
186
- [capistrano-extensions]: Backs up target deployable environment's shared content (identified by the FROM environment
187
- variable, which defaults to 'production') and restores it to the remote environment identified
188
- by the TO envrionment variable, which defaults to "staging."
189
-
190
- Because multiple capistrano configurations must be loaded, an external executable
191
- (capistrano-extensions-sync_content) is invoked, which independently calls capistrano. See the
192
- executable at $GEM_HOME/capistrano-extensions-0.1.2/bin/capistrano-extensions-sync_content
193
-
194
- $> cap remote:sync_content FROM=production TO=staging
195
- DESC
196
- task :sync_content do
197
- system("capistrano-extensions-sync-content #{ENV['FROM'] || 'production'} #{ENV['TO'] || 'staging'}")
198
- end
199
-
200
152
  desc <<-DESC
201
153
  [capistrano-extensions]: Wrapper fro remote:sync_db and remote:sync_content.
202
154
  $> cap remote:sync FROM=production TO=staging
@@ -209,116 +161,42 @@ Capistrano::Configuration.instance(:must_exist).load do
209
161
 
210
162
  namespace :local do
211
163
  desc <<-DESC
212
- [capistrano-extensions]: Backs up deployable environment's database (identified by the
213
- RAILS_ENV environment variable, which defaults to 'production') and copies it to the local machine
214
- DESC
215
- task :backup_db, :roles => :db do
216
- pass_str = pluck_pass_str(db)
217
-
218
- run "mysqldump -u#{db['username']} #{pass_str} #{db['database']} > #{shared_path}/db_backup.sql"
219
- run "gzip #{shared_path}/db_backup.sql"
220
- get "#{shared_path}/db_backup.sql.gz", "#{application}-#{rails_env}-db.sql.gz"
221
- run "rm -f #{shared_path}/db_backup.sql.gz #{shared_path}/db_backup.sql"
222
- end
223
-
224
- desc <<-DESC
225
- [capistrano-extensions] Untars the backup file downloaded from local:backup_db (specified via the FROM env
226
- variable, which defalts to RAILS_ENV), and imports (via mysql command line tool) it back into the database
227
- defined in the RAILS_ENV env variable.
228
-
229
- ToDo: implement proper rollback: currently, if the mysql import succeeds, but the rm fails,
230
- the database won't be rolled back. Not sure this is even all that important or necessary, since
231
- it's a local database that doesn't demand integrity (in other words, you're still going to have to
232
- fix it, but it's not mission critical).
233
- DESC
234
- task :restore_db, :roles => :db do
235
- on_rollback { "gzip #{application}-#{from}-db.sql"}
236
-
237
- from = ENV['FROM'] || rails_env
238
-
239
- env = ENV['RESTORE_ENV'] || 'development'
240
- y = YAML.load_file(local_db_conf(env))[env]
241
- db, user = y['database'], (y['username'] || 'root') # update me!
242
-
243
- pass_str = pluck_pass_str(y)
244
-
245
- puts "\033[1;41m Restoring database backup to #{env} environment \033[0m"
246
- # local
247
- system <<-CMD
248
- gunzip #{application}-#{from}-db.sql.gz &&
249
- mysql -u#{user} #{pass_str} #{db} < #{application}-#{from}-db.sql
250
- CMD
251
- end
252
-
253
- desc <<-DESC
254
- [capistrano-extensions]: Downloads a tarball of uploaded content (that lives in public/
255
- directory, as specified by the :content_directories property) from the production site
256
- back to the local filesystem
164
+ [capistrano-extensions]: Wrapper for local:sync_db and local:sync_content
165
+ $> cap local:sync RAILS_ENV=production RESTORE_ENV=development
257
166
  DESC
258
- task :backup_content do
259
- folders = ["content"] + shared_content.keys
260
-
261
- run "cd #{shared_path} && tar czf #{shared_path}/content_backup.tar.gz #{folders.join(' ')}"
262
-
263
- #run "cd #{content_path} && tar czf #{shared_path}/content_backup.tar.gz *"
264
- download("#{shared_path}/content_backup.tar.gz", "#{application}-#{rails_env}-content_backup.tar.gz")
265
- run "rm -f #{shared_path}/content_backup.tar.gz"
167
+ task :sync do
168
+ sync_db
169
+ sync_content
266
170
  end
171
+ end
172
+
173
+ namespace :util do
267
174
 
268
- desc <<-DESC
269
- [capistrano-extensions]: Restores the backed up content (evn var FROM specifies which environment
270
- was backed up, defaults to RAILS_ENV) to the local development environment app
271
- DESC
272
- task :restore_content do
273
- from = ENV['FROM'] || rails_env
274
-
275
- system "mkdir -p tmp/content-#{from}"
276
- system "tar xzf #{application}-#{from}-content_backup.tar.gz -C tmp/content-#{from}"
277
- system "rm -f #{application}-#{from}-content_backup.tar.gz"
278
-
279
- shared_content.each_pair do |remote, local|
280
- system "rm -rf #{local} && mv tmp/content-#{from}/#{remote} #{local}"
175
+ namespace :tmp do
176
+ desc "[capistrano-extensions]: Displays warning if :tmp_dir has more than 10 files or is greater than 50MB"
177
+ task :check do
178
+ #[ 5 -le "`ls -1 tmp/cap | wc -l`" ] && echo "Display Me"
179
+ cmd = %Q{ [ 10 -le "`ls -1 #{tmp_dir} | wc -l`" ] || [ 50 -le "`du -sh #{tmp_dir} | awk '{print int($1)}'`" ] && printf "\033[1;41m Clean up #{tmp_dir} directory \033[0m\n" && du -sh #{tmp_dir}/* }
180
+ system(cmd)
281
181
  end
282
182
 
283
- content_directories.each do |public_dir|
284
- system "rm -rf public/#{public_dir}"
285
- system "mv tmp/content-#{from}/content/#{public_dir} public/"
286
- end
287
-
288
- end
289
-
290
- desc <<-DESC
291
- [capistrano-extensions]: Wrapper for local:backup_db and local:restore_db.
292
- $> cap local:sync_db RAILS_ENV=production RESTORE_ENV=development
293
- DESC
294
- task :sync_db do
295
- transaction do
296
- backup_db
297
- ENV['FROM'] = rails_env
298
- restore_db
299
- end
300
- end
301
-
302
- desc <<-DESC
303
- [capistrano-extensions]: Wrapper for local:backup_content and local:restore_content
304
- $> cap local:sync_content RAILS_ENV=production RESTORE_ENV=development
305
- DESC
306
- task :sync_content do
307
- transaction do
308
- backup_content
309
- restore_content
183
+ desc "[capistrano-extensions]: Remove the current remote env's backups from :tmp_dir"
184
+ task :clean_remote do
185
+ system("rm -f #{tmp_dir}/#{application}-#{rails_env}*")
310
186
  end
311
- end
312
187
 
313
- desc <<-DESC
314
- [capistrano-extensions]: Wrapper for local:sync_db and local:sync_content
315
- $> cap local:sync RAILS_ENV=production RESTORE_ENV=development
316
- DESC
317
- task :sync do
318
- sync_db
319
- sync_content
188
+ # desc "Removes all but a single backup from :tmp_dir"
189
+ # task :clean do
190
+ #
191
+ # end
192
+ #
193
+ # desc "Removes all tmp files from :tmp_dir"
194
+ # task :remove do
195
+ #
196
+ # end
320
197
  end
321
198
  end
199
+
322
200
  end
323
201
 
324
202
  def pluck_pass_str(db_config)
@@ -327,4 +205,42 @@ def pluck_pass_str(db_config)
327
205
  pass_str = "-p#{pass_str.gsub('$', '\$')}"
328
206
  end
329
207
  pass_str || ''
330
- end
208
+ end
209
+
210
+ module LocalUtils
211
+ def current_timestamp
212
+ @current_timestamp ||= Time.now.to_i
213
+ end
214
+
215
+ def local_db_backup_file(args = {})
216
+ env = args[:env] || rails_env
217
+ timestamp = args[:timestamp] || current_timestamp
218
+ "#{tmp_dir}/#{application}-#{env}-db-#{timestamp}.sql"
219
+ end
220
+
221
+ def local_content_backup_dir(args={})
222
+ env = args[:env] || rails_env
223
+ timestamp = args[:timestamp] || current_timestamp
224
+ "#{tmp_dir}/#{application}-#{env}-content-#{timestamp}"
225
+ end
226
+
227
+ def retrieve_local_files(env, type)
228
+ `ls -r #{tmp_dir} | awk -F"-" '{ if ($2 ~ /#{env}/ && $3 ~ /#{type}/) { print $4; } }'`.split(' ')
229
+ end
230
+
231
+ def most_recent_local_backup(env, type)
232
+ retrieve_local_files(env, type).first.to_i
233
+ end
234
+ end
235
+
236
+ module RemoteUtils
237
+ def last_mod_time(path)
238
+ capture("stat -c%Y #{path}").to_i
239
+ end
240
+
241
+ def server_cache_valid?(path)
242
+ capture("[ -f #{path} ] || echo '1'").empty? && ((Time.now.to_i - last_mod_time(path)) <= remote_backup_expires) # two days in seconds
243
+ end
244
+ end
245
+
246
+ include LocalUtils, RemoteUtils
@@ -0,0 +1,103 @@
1
+ namespace :remote do
2
+ desc <<-DESC
3
+ [capistrano-extensions]: Uploads the backup file downloaded from local:backup_content (specified via the
4
+ FROM env variable), copies it to the remote environment specified by RAILS_ENV, and unpacks it into the
5
+ shared/ directory.
6
+ DESC
7
+ task :restore_content do
8
+ from = ENV['FROM'] || 'production'
9
+
10
+ if deployable_environments.include?(rails_env.to_sym)
11
+ generate_remote_content_backup if store_remote_backups
12
+
13
+ local_backup_file = local_content_backup_dir(:timestamp => most_recent_local_backup(from, 'content'), :env => from) + ".tar.#{zip_ext}"
14
+ remote_dir = "#{shared_path}/restore_#{from}_content"
15
+ remote_file = "#{remote_dir}.tar.#{zip_ext}"
16
+
17
+ if !File.exists?(local_backup_file)
18
+ puts "Could not find backup file: #{local_backup_file}"
19
+ exit 1
20
+ end
21
+
22
+ upload(local_backup_file, "#{remote_file}")
23
+ remote_dirs = [content_dir] + shared_content.keys
24
+
25
+ run("cd #{shared_path} && rm -rf #{remote_dirs.join(' ')} && tar xzf #{remote_file} -C #{shared_path}/")
26
+ end
27
+ end
28
+
29
+ desc <<-DESC
30
+ [capistrano-extensions]: Backs up remote server's shared content and restores it to a separate remote server.
31
+ $> cap remote:sync_content FROM=production TO=staging
32
+ DESC
33
+ task :sync_content do
34
+ system("capistrano-extensions-sync-content #{ENV['FROM'] || 'production'} #{ENV['TO'] || 'staging'}")
35
+ end
36
+ end
37
+
38
+ namespace :local do
39
+ desc <<-DESC
40
+ [capistrano-extensions]: Downloads a tarball of shared content (identified by the :shared_content and
41
+ :content_directories properties) from a deployable environment (RAILS_ENV) to the local filesystem.
42
+ DESC
43
+ task :backup_content do
44
+ # sort by last alphabetically (forcing the most recent timestamp to the top)
45
+ files = retrieve_local_files(rails_env, 'content')
46
+
47
+ if files.empty?
48
+ # pull it from the server
49
+ generate_remote_content_backup unless server_cache_valid?(content_backup_file)
50
+ system("mkdir -p #{tmp_dir}")
51
+ download(content_backup_file, "#{local_content_backup_dir}.tar.#{zip_ext}")
52
+ else
53
+ # set us up to use our local cache
54
+ @current_timestamp = files.first.to_i # actually has the extension hanging off of it, but shouldn't be a problem
55
+ end
56
+ # Notify user if :tmp_dir is too large
57
+ util::tmp::check
58
+ end
59
+
60
+ desc <<-DESC
61
+ [capistrano-extensions]: Restores the backed up content (env var FROM specifies which environment
62
+ was backed up, defaults to RAILS_ENV) to the local development environment app
63
+ DESC
64
+ task :restore_content do
65
+ from = ENV['FROM'] || rails_env
66
+
67
+ local_dir = local_content_backup_dir(:env => from)
68
+ system "mkdir -p #{local_dir}"
69
+ system "tar xzf #{local_dir}.tar.#{zip_ext} -C #{local_dir}"
70
+
71
+ shared_content.each_pair do |remote, local|
72
+ system "rm -rf #{local} && mv #{local_dir}/#{remote} #{local}"
73
+ end
74
+
75
+ content_directories.each do |public_dir|
76
+ system "rm -rf public/#{public_dir}"
77
+ system "mv #{local_dir}/content/#{public_dir} public/"
78
+ end
79
+
80
+ system "rm -rf #{local_dir}"
81
+ end
82
+
83
+
84
+ desc <<-DESC
85
+ [capistrano-extensions]: Wrapper for local:backup_content and local:restore_content
86
+ $> cap local:sync_content RAILS_ENV=production RESTORE_ENV=development
87
+ DESC
88
+ task :sync_content do
89
+ transaction do
90
+ backup_content
91
+ restore_content
92
+ end
93
+ end
94
+ end
95
+
96
+ def content_backup_file
97
+ "#{shared_path}/backup_#{rails_env}_content.tar.#{zip_ext}"
98
+ end
99
+
100
+ def generate_remote_content_backup
101
+ folders = [content_dir] + shared_content.keys
102
+ run "cd #{shared_path} && tar czf #{content_backup_file} #{folders.join(' ')}"
103
+ end
@@ -0,0 +1,136 @@
1
+ namespace :remote do
2
+ desc <<-DESC
3
+ [capistrano-extensions] Uploads the backup file downloaded from local:backup_db (specified via the FROM env variable),
4
+ copies it to the remote environment specified by RAILS_ENV, and imports (via mysql command line tool) it back into the
5
+ remote database.
6
+ DESC
7
+ task :restore_db, :roles => :db do
8
+ env = ENV['FROM'] || 'production'
9
+
10
+ puts "\033[1;41m Restoring database backup to #{rails_env} environment \033[0m"
11
+ if deployable_environments.include?(rails_env.to_sym)
12
+ generate_remote_db_backup if store_remote_backups
13
+
14
+ # remote environment
15
+ local_backup_file = local_db_backup_file(:timestamp => most_recent_local_backup(env, 'db'), :env => env) + ".#{zip_ext}"
16
+ remote_file = "#{shared_path}/restore_#{env}_db.sql"
17
+
18
+ if !File.exists?(local_backup_file)
19
+ puts "Could not find backup file: #{local_backup_file}"
20
+ exit 1
21
+ end
22
+ upload(local_backup_file, "#{remote_file}.#{zip_ext}")
23
+
24
+ pass_str = pluck_pass_str(db)
25
+ run "#{unzip} -c #{remote_file}.#{zip_ext} > #{remote_file}"
26
+ run "mysql -u#{db['username']} #{pass_str} #{db['database']} < #{remote_file}"
27
+ run "rm -f #{remote_file}"
28
+ end
29
+ end
30
+
31
+ desc <<-DESC
32
+ [capistrano-extensions]: Backs up target deployable environment's database (identified
33
+ by the FROM environment variable, which defaults to 'production') and restores it to
34
+ the remote database identified by the TO environment variable, which defaults to "staging."
35
+ DESC
36
+ task :sync_db do
37
+ system("capistrano-extensions-sync-db #{ENV['FROM'] || 'production'} #{ENV['TO'] || 'staging'}")
38
+ end
39
+ end
40
+
41
+ namespace :local do
42
+ desc <<-DESC
43
+ [capistrano-extensions]: Backs up deployable environment's database (identified by the
44
+ RAILS_ENV environment variable, which defaults to 'production') and copies it to the local machine
45
+ DESC
46
+ task :backup_db, :roles => :db do
47
+
48
+ # sort by last alphabetically (forcing the most recent timestamp to the top)
49
+ files = retrieve_local_files(rails_env, 'db')
50
+
51
+ if files.empty?
52
+ # pull it from the server
53
+ generate_remote_db_backup unless server_cache_valid?(db_backup_zip_file)
54
+ system "mkdir -p #{tmp_dir}"
55
+ download(db_backup_zip_file, "#{local_db_backup_file}.#{zip_ext}")
56
+ else
57
+ # set us up to use our local cache
58
+ @current_timestamp = files.first.to_i # actually has the extension hanging off of it, but shouldn't be a problem
59
+ end
60
+ end
61
+
62
+ desc <<-DESC
63
+ [capistrano-extensions] Untars the backup file downloaded from local:backup_db (specified via the FROM env
64
+ variable, which defalts to RAILS_ENV), and imports (via mysql command line tool) it back into the database
65
+ defined in the RESTORE_ENV env variable (defaults to development).
66
+ DESC
67
+ task :restore_db, :roles => :db do
68
+ from = ENV['FROM'] || rails_env
69
+ env = ENV['RESTORE_ENV'] || 'development'
70
+
71
+ y = YAML.load_file(local_db_conf(env))[env]
72
+ db, user = y['database'], (y['username'] || 'root') # update me!
73
+
74
+ pass_str = pluck_pass_str(y)
75
+ mysql_str = "mysql -u#{user} #{pass_str} #{db}"
76
+ mysql_dump = "mysqldump --add-drop-database -u#{user} #{pass_str} #{db}"
77
+
78
+ local_backup_file = local_db_backup_file(:env => env)
79
+ remote_backup_file = local_db_backup_file(:env => from)
80
+
81
+ puts "\033[1;41m Restoring database backup to #{env} environment \033[0m"
82
+
83
+ # local
84
+ cmd = ""
85
+ if store_dev_backups
86
+ cmd << <<-CMD
87
+ mkdir -p #{tmp_dir} &&
88
+ #{mysql_dump} | #{zip} > #{local_backup_file}.#{zip_ext} &&
89
+ CMD
90
+ end
91
+ cmd << <<-CMD
92
+ #{unzip} -c #{remote_backup_file}.#{zip_ext} > #{remote_backup_file} &&
93
+ #{mysql_str} < #{remote_backup_file} &&
94
+ rm -f #{remote_backup_file}
95
+ CMD
96
+ system(cmd.strip)
97
+
98
+ # Notify user if :tmp_dir is too large
99
+ util::tmp::check
100
+ end
101
+
102
+ desc <<-DESC
103
+ [capistrano-extensions]: Wrapper for local:backup_db and local:restore_db.
104
+ $> cap local:sync_db RAILS_ENV=production RESTORE_ENV=development
105
+ DESC
106
+ task :sync_db do
107
+ transaction do
108
+ backup_db
109
+ ENV['FROM'] = rails_env
110
+ restore_db
111
+ end
112
+ end
113
+
114
+ desc <<-DESC
115
+ [capistrano-extensions]: Ensure that a fresh remote data dump is retrieved before syncing to the local environment.
116
+ DESC
117
+ task :resync_db do
118
+ util::tmp::clean_remote
119
+ sync_db
120
+ end
121
+
122
+ end
123
+
124
+ def db_backup_file
125
+ "#{shared_path}/backup_#{rails_env}_db.sql"
126
+ end
127
+
128
+ def db_backup_zip_file
129
+ "#{db_backup_file}.#{zip_ext}"
130
+ end
131
+
132
+ def generate_remote_db_backup
133
+ pass_str = pluck_pass_str(db)
134
+ run "mysqldump --add-drop-database -u#{db['username']} #{pass_str} #{db['database']} > #{db_backup_file}"
135
+ run "rm -f #{db_backup_zip_file} && #{zip} #{db_backup_file} && rm -f #{db_backup_file}"
136
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: capistrano-extensions
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.5
4
+ version: 0.1.8
5
5
  platform: ruby
6
6
  authors:
7
7
  - John Trupiano
@@ -9,7 +9,7 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2009-02-22 00:00:00 -05:00
12
+ date: 2009-04-27 00:00:00 -04:00
13
13
  default_executable:
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
@@ -20,7 +20,7 @@ dependencies:
20
20
  requirements:
21
21
  - - ~>
22
22
  - !ruby/object:Gem::Version
23
- version: 2.5.4
23
+ version: 2.5.5
24
24
  version:
25
25
  - !ruby/object:Gem::Dependency
26
26
  name: geminstaller
@@ -30,17 +30,7 @@ dependencies:
30
30
  requirements:
31
31
  - - ~>
32
32
  - !ruby/object:Gem::Version
33
- version: 0.5.0
34
- version:
35
- - !ruby/object:Gem::Dependency
36
- name: hoe
37
- type: :development
38
- version_requirement:
39
- version_requirements: !ruby/object:Gem::Requirement
40
- requirements:
41
- - - ">="
42
- - !ruby/object:Gem::Version
43
- version: 1.8.2
33
+ version: 0.5.1
44
34
  version:
45
35
  description: A base set of Capistrano extensions-- aids with the file_column plugin, the GemInstaller gem, multiple deployable environments, logfile helpers, and database/asset synchronization from production to local environment
46
36
  email: jtrupiano@gmail.com
@@ -50,27 +40,28 @@ executables:
50
40
  extensions: []
51
41
 
52
42
  extra_rdoc_files:
53
- - History.txt
54
- - Manifest.txt
55
- - README.txt
43
+ - README.rdoc
56
44
  files:
57
45
  - History.txt
46
+ - ISSUES.txt
58
47
  - Manifest.txt
59
- - README.txt
60
- - Rakefile
48
+ - README.rdoc
49
+ - VERSION.yml
61
50
  - bin/capistrano-extensions-sync-content
62
51
  - bin/capistrano-extensions-sync-db
63
- - capistrano-extensions.gemspec
64
- - lib/capistrano-extensions.rb
52
+ - lib/capistrano-extensions
65
53
  - lib/capistrano-extensions/deploy.rb
66
54
  - lib/capistrano-extensions/geminstaller_dependency.rb
67
- - lib/capistrano-extensions/version.rb
55
+ - lib/capistrano-extensions/recipes
56
+ - lib/capistrano-extensions/recipes/content_sync.rb
57
+ - lib/capistrano-extensions/recipes/db_sync.rb
58
+ - lib/capistrano-extensions.rb
68
59
  has_rdoc: true
69
60
  homepage: http://github.com/jtrupiano/capistrano-extensions
70
61
  post_install_message:
71
62
  rdoc_options:
72
- - --main
73
- - README.txt
63
+ - --inline-source
64
+ - --charset=UTF-8
74
65
  require_paths:
75
66
  - lib
76
67
  required_ruby_version: !ruby/object:Gem::Requirement
data/README.txt DELETED
@@ -1,53 +0,0 @@
1
- = capistrano-extensions
2
-
3
- * http://github.com/jtrupiano/capistrano-extensions
4
-
5
- == DESCRIPTION/FEATURES:
6
-
7
- This gem provides a base set of Capistrano extensions including the following:
8
- * a new :gemfile RemoteDependency type
9
- * tasks/helpers for handling public and private asset folders (e.g. created by the file_column plugin)
10
- * tasks/helpers for auto-syncing server gems (via integration with Chad Wooley's GemInstaller gem)
11
- * helpers for dealing with multiple deployable environments (e.g. staging, prodtest, production)
12
- * tasks for working with remote logfiles
13
- * tasks for database/asset synchronization from production back to local environments
14
-
15
- For a detailed exploration of these features, check out the wiki: http://github.com/jtrupiano/capistrano-extensions/wikis/home
16
-
17
- == SYNOPSIS:
18
-
19
- FIX (code sample of usage)
20
-
21
- == REQUIREMENTS:
22
-
23
- * Capistrano ~> 2.5.4
24
- * GemInstaller ~> 0.5.0
25
-
26
- == INSTALL:
27
-
28
- * sudo gem install capistrano-extensions
29
-
30
- == LICENSE:
31
-
32
- (The MIT License)
33
-
34
- Copyright (c) 2008 FIX
35
-
36
- Permission is hereby granted, free of charge, to any person obtaining
37
- a copy of this software and associated documentation files (the
38
- 'Software'), to deal in the Software without restriction, including
39
- without limitation the rights to use, copy, modify, merge, publish,
40
- distribute, sublicense, and/or sell copies of the Software, and to
41
- permit persons to whom the Software is furnished to do so, subject to
42
- the following conditions:
43
-
44
- The above copyright notice and this permission notice shall be
45
- included in all copies or substantial portions of the Software.
46
-
47
- THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
48
- EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
49
- MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
50
- IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
51
- CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
52
- TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
53
- SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/Rakefile DELETED
@@ -1,35 +0,0 @@
1
- # -*- ruby -*-
2
-
3
- require 'rubygems'
4
- require 'hoe'
5
- require './lib/capistrano-extensions.rb'
6
- require "./lib/capistrano-extensions/version"
7
-
8
- PKG_NAME = "capistrano-extensions"
9
- PKG_BUILD = ENV['PKG_BUILD'] ? '.' + ENV['PKG_BUILD'] : ''
10
- version = CapistranoExtensions::Version::STRING.dup
11
- if ENV['SNAPSHOT'].to_i == 1
12
- version << "." << Time.now.utc.strftime("%Y%m%d%H%M%S")
13
- end
14
- PKG_VERSION = version
15
- PKG_FILE_NAME = "#{PKG_NAME}-#{PKG_VERSION}"
16
-
17
- Hoe.new(PKG_NAME, PKG_VERSION) do |p|
18
- p.rubyforge_name = 'johntrupiano' # if different than lowercase project name
19
- p.developer('John Trupiano', 'jtrupiano@gmail.com')
20
- p.name = PKG_NAME
21
- p.version = PKG_VERSION
22
- #p.platform = Gem::Platform::RUBY
23
- p.author = "John Trupiano"
24
- p.email = "jtrupiano@gmail.com"
25
- p.description = %q(A base set of Capistrano extensions-- aids with the file_column plugin, the GemInstaller gem, multiple deployable environments, logfile helpers, and database/asset synchronization from production to local environment)
26
- p.summary = p.description # More details later??
27
- p.remote_rdoc_dir = PKG_NAME # Release to /PKG_NAME
28
- # p.changes = p.paragraphs_of('CHANGELOG', 0..1).join("\n\n")
29
- p.extra_deps << ["capistrano", "~> 2.5.4"]
30
- p.extra_deps << ["geminstaller", "~> 0.5.0"]
31
- p.need_zip = true
32
- p.need_tar = false
33
- end
34
-
35
- # vim: syntax=Ruby
@@ -1,39 +0,0 @@
1
- Gem::Specification.new do |s|
2
- s.name = %q{capistrano-extensions}
3
- s.version = "0.1.4"
4
-
5
- s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
6
- s.authors = ["John Trupiano"]
7
- s.date = %q{2008-09-12}
8
- s.description = %q{A base set of Capistrano extensions-- aids with the file_column plugin, the GemInstaller gem, multiple deployable environments, logfile helpers, and database/asset synchronization from production to local environment}
9
- s.email = %q{jtrupiano@gmail.com}
10
- s.executables = ["capistrano-extensions-sync-content", "capistrano-extensions-sync-db"]
11
- s.extra_rdoc_files = ["History.txt", "Manifest.txt", "README.txt"]
12
- s.files = ["History.txt", "Manifest.txt", "README.txt", "Rakefile", "bin/capistrano-extensions-sync-content", "bin/capistrano-extensions-sync-db", "lib/capistrano-extensions.rb", "lib/capistrano-extensions/deploy.rb", "lib/capistrano-extensions/geminstaller_dependency.rb", "lib/capistrano-extensions/version.rb"]
13
- s.has_rdoc = true
14
- s.homepage = %q{http://github.com/jtrupiano/capistrano-extensions}
15
- s.rdoc_options = ["--main", "README.txt"]
16
- s.require_paths = ["lib"]
17
- s.rubyforge_project = %q{johntrupiano}
18
- s.rubygems_version = %q{1.2.0}
19
- s.summary = %q{A base set of Capistrano extensions-- aids with the file_column plugin, the GemInstaller gem, multiple deployable environments, logfile helpers, and database/asset synchronization from production to local environment}
20
-
21
- if s.respond_to? :specification_version then
22
- current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
23
- s.specification_version = 2
24
-
25
- if current_version >= 3 then
26
- s.add_runtime_dependency(%q<capistrano>, [">= 2.4.3"])
27
- s.add_runtime_dependency(%q<geminstaller>, [">= 0.4.3"])
28
- s.add_development_dependency(%q<hoe>, [">= 1.7.0"])
29
- else
30
- s.add_dependency(%q<capistrano>, [">= 2.4.3"])
31
- s.add_dependency(%q<geminstaller>, [">= 0.4.3"])
32
- s.add_dependency(%q<hoe>, [">= 1.7.0"])
33
- end
34
- else
35
- s.add_dependency(%q<capistrano>, [">= 2.4.3"])
36
- s.add_dependency(%q<geminstaller>, [">= 0.4.3"])
37
- s.add_dependency(%q<hoe>, [">= 1.7.0"])
38
- end
39
- end
@@ -1,20 +0,0 @@
1
- module CapistranoExtensions
2
- module Version #:nodoc:
3
- # A method for comparing versions of required modules. It expects two
4
- # arrays of integers as parameters, the first being the minimum version
5
- # required, and the second being the actual version available. It returns
6
- # true if the actual version is at least equal to the required version.
7
- def self.check(required, actual) #:nodoc:
8
- required = required.map { |v| "%06d" % v }.join(".")
9
- actual = actual.map { |v| "%06d" % v }.join(".")
10
- return actual >= required
11
- end
12
-
13
- MAJOR = 0
14
- MINOR = 1
15
- TINY = 5
16
-
17
- STRING = [MAJOR, MINOR, TINY].join(".")
18
- end
19
- end
20
-