quapistrano 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +49 -0
- data/Gemfile +15 -0
- data/Gemfile.lock +45 -0
- data/LICENSE.txt +20 -0
- data/README.rdoc +62 -0
- data/Rakefile +55 -0
- data/VERSION +1 -0
- data/lib/quapistrano/helper.rb +9 -0
- data/lib/quapistrano/recipes/db.rb +171 -0
- data/lib/quapistrano/recipes/shared.rb +43 -0
- data/lib/quapistrano/recipes/unicorn.rb +88 -0
- data/lib/quapistrano/support/common.rb +31 -0
- metadata +118 -0
data/.gitignore
ADDED
@@ -0,0 +1,49 @@
|
|
1
|
+
# rcov generated
|
2
|
+
coverage
|
3
|
+
coverage.data
|
4
|
+
|
5
|
+
# rdoc generated
|
6
|
+
rdoc
|
7
|
+
|
8
|
+
# yard generated
|
9
|
+
doc
|
10
|
+
.yardoc
|
11
|
+
|
12
|
+
# bundler
|
13
|
+
.bundle
|
14
|
+
|
15
|
+
# jeweler generated
|
16
|
+
pkg
|
17
|
+
|
18
|
+
# Have editor/IDE/OS specific files you need to ignore? Consider using a global gitignore:
|
19
|
+
#
|
20
|
+
# * Create a file at ~/.gitignore
|
21
|
+
# * Include files you want ignored
|
22
|
+
# * Run: git config --global core.excludesfile ~/.gitignore
|
23
|
+
#
|
24
|
+
# After doing this, these files will be ignored in all your git projects,
|
25
|
+
# saving you from having to 'pollute' every project you touch with them
|
26
|
+
#
|
27
|
+
# Not sure what to needs to be ignored for particular editors/OSes? Here's some ideas to get you started. (Remember, remove the leading # of the line)
|
28
|
+
#
|
29
|
+
# For MacOS:
|
30
|
+
#
|
31
|
+
.DS_Store
|
32
|
+
|
33
|
+
# For TextMate
|
34
|
+
#*.tmproj
|
35
|
+
#tmtags
|
36
|
+
|
37
|
+
# For emacs:
|
38
|
+
#*~
|
39
|
+
#\#*
|
40
|
+
#.\#*
|
41
|
+
|
42
|
+
# For vim:
|
43
|
+
#*.swp
|
44
|
+
|
45
|
+
# For redcar:
|
46
|
+
#.redcar
|
47
|
+
|
48
|
+
# For rubinius:
|
49
|
+
#*.rbc
|
data/Gemfile
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
source "http://rubygems.org"
|
2
|
+
# Add dependencies required to use your gem here.
|
3
|
+
# Example:
|
4
|
+
# gem "activesupport", ">= 2.3.5"
|
5
|
+
|
6
|
+
# Add dependencies to develop your gem here.
|
7
|
+
# Include everything needed to run rake, tests, features, etc.
|
8
|
+
|
9
|
+
gem "capistrano"
|
10
|
+
|
11
|
+
group :development do
|
12
|
+
gem "bundler"
|
13
|
+
gem "jeweler", "~> 1.8.3"
|
14
|
+
gem "rspec"
|
15
|
+
end
|
data/Gemfile.lock
ADDED
@@ -0,0 +1,45 @@
|
|
1
|
+
GEM
|
2
|
+
remote: http://rubygems.org/
|
3
|
+
specs:
|
4
|
+
capistrano (2.11.2)
|
5
|
+
highline
|
6
|
+
net-scp (>= 1.0.0)
|
7
|
+
net-sftp (>= 2.0.0)
|
8
|
+
net-ssh (>= 2.0.14)
|
9
|
+
net-ssh-gateway (>= 1.1.0)
|
10
|
+
diff-lcs (1.1.3)
|
11
|
+
git (1.2.5)
|
12
|
+
highline (1.6.11)
|
13
|
+
jeweler (1.8.3)
|
14
|
+
bundler (~> 1.0)
|
15
|
+
git (>= 1.2.5)
|
16
|
+
rake
|
17
|
+
rdoc
|
18
|
+
json (1.6.6)
|
19
|
+
net-scp (1.0.4)
|
20
|
+
net-ssh (>= 1.99.1)
|
21
|
+
net-sftp (2.0.5)
|
22
|
+
net-ssh (>= 2.0.9)
|
23
|
+
net-ssh (2.3.0)
|
24
|
+
net-ssh-gateway (1.1.0)
|
25
|
+
net-ssh (>= 1.99.1)
|
26
|
+
rake (0.9.2.2)
|
27
|
+
rdoc (3.12)
|
28
|
+
json (~> 1.4)
|
29
|
+
rspec (2.9.0)
|
30
|
+
rspec-core (~> 2.9.0)
|
31
|
+
rspec-expectations (~> 2.9.0)
|
32
|
+
rspec-mocks (~> 2.9.0)
|
33
|
+
rspec-core (2.9.0)
|
34
|
+
rspec-expectations (2.9.1)
|
35
|
+
diff-lcs (~> 1.1.3)
|
36
|
+
rspec-mocks (2.9.0)
|
37
|
+
|
38
|
+
PLATFORMS
|
39
|
+
ruby
|
40
|
+
|
41
|
+
DEPENDENCIES
|
42
|
+
bundler
|
43
|
+
capistrano
|
44
|
+
jeweler (~> 1.8.3)
|
45
|
+
rspec
|
data/LICENSE.txt
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2012 Tiago Melo
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.rdoc
ADDED
@@ -0,0 +1,62 @@
|
|
1
|
+
= Quapistrano
|
2
|
+
|
3
|
+
A 'Work in Progress' gem with several recipes for capistrano, using a clean approach, delegating dawting tasks to provisioners.
|
4
|
+
For now, it features mysql workflow management with backup support, unicorn start/stop restart/reload and shared assets' synchronization.
|
5
|
+
|
6
|
+
== Recipes
|
7
|
+
|
8
|
+
[db]
|
9
|
+
Manage DB tasks. Currently supports mysql only. It has the following tasks:
|
10
|
+
* (local|remote):backup - creates a local/remote snapshot of the current database state
|
11
|
+
* (local|remote):cleanup - cleans up local/remote backup leaving up to a specified number of backups (<tt>db_backup_count</tt>)
|
12
|
+
* (local|remote):restore - restores the local/remote database to the latest backup found in the backup directory (<tt>db_backup_dir</tt>)
|
13
|
+
* (local|remote):setup - creates the backup folder in the given directory (<tt>db_backup_dir</tt> for remote and <tt>db_backup_local_dir</tt> for local)
|
14
|
+
* (local|remote):sync - syncs the local/remote database with its counterpart (<tt>cap local:sync</tt> syncs local database with the remote's state)
|
15
|
+
* remote:download - downloads the current remote database state (also creates a backup)
|
16
|
+
* remote:upload - uploads the latest local backup (does not create a backup of either of the databses)
|
17
|
+
* remote:create_database - creates the database in the remote (used after <tt>deploy:setup</tt>)
|
18
|
+
|
19
|
+
The *db* recipe also adds hooks to <tt>deploy:setup</tt>, <tt>deploy:cleanup</tt> (with the corresponding local/remote tasks) and runs <tt>remote:backup</tt> before <tt>deploy:migrate</tt>.
|
20
|
+
|
21
|
+
[unicorn]
|
22
|
+
Manages Unicorn in-production workflow. Supports the following tasks:
|
23
|
+
* unicorn:setup - creates a folder to place the socket files (to be used in <tt>deploy:setup</tt>, can be changed through <tt>unicorn_socket</tt>)
|
24
|
+
* unicorn:start - starts unicorn in daemon mode. It uses bundler if the bundler recipe is included - i.e. <tt>bundler exec unicorn_rails ...</tt> (uses <tt>unicorn_bin</tt> and <tt>unicorn_config</tt>)
|
25
|
+
* unicorn:stop - stops the unicorn daemon by reading the pid file (uses <tt>pids_path</tt>)
|
26
|
+
* unicorn:reload - reloads unicorn configuration (usually done after <tt>deploy:upload</tt>)
|
27
|
+
* unicorn:restart - restarts unicorn daemon, using the current release (after <tt>deploy:update</tt>)
|
28
|
+
* unicorn:status - lists unicorn's running processes
|
29
|
+
|
30
|
+
The *unicorn* recipe links <tt>deploy:restart</tt> to <tt>unicorn:restart</tt> and runs <tt>unicorn:setup</tt> after <tt>deploy:setup</tt>
|
31
|
+
|
32
|
+
[shared]
|
33
|
+
Manages shared paths. Paths are given in Hash form (i.e. <tt>{ 'uploads' => 'public/uploads' }</tt>) through the variable <tt>shared_folders</tt>, in which the key is the shared folder path (<tt>www/shared/uploads</tt>) and the value is the symlink path (<tt>current/public/uploads</tt>). Supports:
|
34
|
+
* shared:local:sync - Syncs local folders with remote ones
|
35
|
+
* shared:remote:setup - Creates the folders
|
36
|
+
* shared:remote:symlink - Creates the symlinks
|
37
|
+
* shared:remote:sync - Syncs the remote folders with the local ones
|
38
|
+
|
39
|
+
The *shared* recipe adds a <tt>deploy:setup</tt> hook and runs <tt>shared:remote:symlink</tt> after <tt>deploy:update</tt>
|
40
|
+
|
41
|
+
== TODO
|
42
|
+
|
43
|
+
* Make tests
|
44
|
+
* Update README with usage instructions
|
45
|
+
* More recipes (ssh, bluepill, etc)
|
46
|
+
|
47
|
+
|
48
|
+
== Contributing to Quapistrano
|
49
|
+
|
50
|
+
* Check out the latest master to make sure the feature hasn't been implemented or the bug hasn't been fixed yet.
|
51
|
+
* Check out the issue tracker to make sure someone already hasn't requested it and/or contributed it.
|
52
|
+
* Fork the project.
|
53
|
+
* Start a feature/bugfix branch.
|
54
|
+
* Commit and push until you are happy with your contribution.
|
55
|
+
* Make sure to add tests for it. This is important so I don't break it in a future version unintentionally.
|
56
|
+
* Please try not to mess with the Rakefile, version, or history. If you want to have your own version, or is otherwise necessary, that is fine, but please isolate to its own commit so I can cherry-pick around it.
|
57
|
+
|
58
|
+
== Copyright
|
59
|
+
|
60
|
+
Copyright (c) 2012 Tiago Melo. See LICENSE.txt for
|
61
|
+
further details.
|
62
|
+
|
data/Rakefile
ADDED
@@ -0,0 +1,55 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require 'rubygems'
|
4
|
+
require 'bundler'
|
5
|
+
begin
|
6
|
+
Bundler.setup(:default, :development)
|
7
|
+
rescue Bundler::BundlerError => e
|
8
|
+
$stderr.puts e.message
|
9
|
+
$stderr.puts "Run `bundle install` to install missing gems"
|
10
|
+
exit e.status_code
|
11
|
+
end
|
12
|
+
require 'rake'
|
13
|
+
|
14
|
+
require 'jeweler'
|
15
|
+
Jeweler::Tasks.new do |gem|
|
16
|
+
# gem is a Gem::Specification... see http://docs.rubygems.org/read/chapter/20 for more options
|
17
|
+
gem.name = "quapistrano"
|
18
|
+
gem.homepage = "http://github.com/tiagoblackcode/quapistrano"
|
19
|
+
gem.license = "MIT"
|
20
|
+
gem.summary = %Q{Yet another recipes gem for capistrano}
|
21
|
+
gem.description = %Q{A 'Work in Progress' gem with several recipes for capistrano, using a clean approach, delegating dawting tasks to provisioners}
|
22
|
+
gem.email = "tiago.blackcode@gmail.com"
|
23
|
+
gem.authors = ["Tiago Melo"]
|
24
|
+
gem.files = FileList["[A-Z]*", "{lib, spec}/**/*", ".gitignore"]
|
25
|
+
gem.add_dependency 'capistrano'
|
26
|
+
# dependencies defined in Gemfile
|
27
|
+
end
|
28
|
+
Jeweler::RubygemsDotOrgTasks.new
|
29
|
+
|
30
|
+
#require 'rake/testtask'
|
31
|
+
#Rake::TestTask.new(:test) do |test|
|
32
|
+
# test.libs << 'lib' << 'test'
|
33
|
+
# test.pattern = 'test/**/test_*.rb'
|
34
|
+
# test.verbose = true
|
35
|
+
#end
|
36
|
+
|
37
|
+
#require 'simplecov/rcovtask'
|
38
|
+
#Rcov::RcovTask.new do |test|
|
39
|
+
# test.libs << 'test'
|
40
|
+
# test.pattern = 'test/**/test_*.rb'
|
41
|
+
# test.verbose = true
|
42
|
+
# test.rcov_opts << '--exclude "gems/*"'
|
43
|
+
#end
|
44
|
+
|
45
|
+
#task :default => :test
|
46
|
+
|
47
|
+
require 'rdoc/task'
|
48
|
+
Rake::RDocTask.new do |rdoc|
|
49
|
+
version = File.exist?('VERSION') ? File.read('VERSION') : ""
|
50
|
+
|
51
|
+
rdoc.rdoc_dir = 'rdoc'
|
52
|
+
rdoc.title = "quapistrano #{version}"
|
53
|
+
rdoc.rdoc_files.include('README*')
|
54
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
55
|
+
end
|
data/VERSION
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
1.0.0
|
@@ -0,0 +1,171 @@
|
|
1
|
+
require 'quapistrano/helper'
|
2
|
+
|
3
|
+
Capistrano::Configuration.instance(true).load do
|
4
|
+
_cset :backup_dir, "#{shared_dir}/backup"
|
5
|
+
|
6
|
+
_cset :mysqldump_bin, "mysqldump"
|
7
|
+
|
8
|
+
_cset :db_backup_count, 5
|
9
|
+
|
10
|
+
_cset (:backup_path) { File.join(deploy_to, backup_dir) }
|
11
|
+
_cset (:db_backup_dir) { File.join(backup_dir, 'db') }
|
12
|
+
_cset (:db_backup_path) { File.join(deploy_to, db_backup_dir) }
|
13
|
+
|
14
|
+
|
15
|
+
_cset :db_backup_local_dir, "db/backup"
|
16
|
+
|
17
|
+
|
18
|
+
after 'deploy:setup' do
|
19
|
+
db.local.setup
|
20
|
+
db.remote.setup
|
21
|
+
end
|
22
|
+
|
23
|
+
after 'deploy:cleanup' do
|
24
|
+
db.remote.cleanup
|
25
|
+
end
|
26
|
+
|
27
|
+
before 'deploy:migrate' do
|
28
|
+
db.remote.backup
|
29
|
+
end
|
30
|
+
|
31
|
+
def db_config(environment = rails_env)
|
32
|
+
@db_config ||= db_config_fetch
|
33
|
+
return @db_config[environment]['username'], @db_config[environment]['password'], @db_config[environment]['database'], @db_config[environment]['adapter']
|
34
|
+
end
|
35
|
+
|
36
|
+
def db_config_fetch
|
37
|
+
require 'yaml'
|
38
|
+
YAML::load_file("config/database.yml")
|
39
|
+
end
|
40
|
+
|
41
|
+
def db_backup_filename
|
42
|
+
@db_backup_filename ||= "#{db_backup_filename_base}.#{Time.now.strftime '%Y%m%d%H%M%S'}.sql.bz2"
|
43
|
+
end
|
44
|
+
|
45
|
+
def db_backup_filename_base
|
46
|
+
"database.#{rails_env}"
|
47
|
+
end
|
48
|
+
|
49
|
+
def db_backup_mysql_cmd(username, password, database)
|
50
|
+
"mysqldump --opt -u #{username} --password=#{password} #{database}"
|
51
|
+
end
|
52
|
+
|
53
|
+
def db_output_and_compress cmd, filename
|
54
|
+
"#{cmd} | bzip2 -9 > #{filename}"
|
55
|
+
end
|
56
|
+
|
57
|
+
def db_restore_mysql_cmd(username, password, database, file_to_restore)
|
58
|
+
"bunzip2 --stdout #{file_to_restore} | mysql -u #{username} --password=#{password} #{database}"
|
59
|
+
end
|
60
|
+
|
61
|
+
def db_create_database_mysql_cmd(username, password, database)
|
62
|
+
sql = "CREATE DATABASE #{database};"
|
63
|
+
"mysql -u #{username} --password=#{password} --execute=\"#{sql}\""
|
64
|
+
end
|
65
|
+
|
66
|
+
def db_backup_cmd filename_to_backup
|
67
|
+
username, password, database, adapter = db_config
|
68
|
+
db_output_and_compress db_backup_mysql_cmd(username, password, database), filename_to_backup
|
69
|
+
end
|
70
|
+
|
71
|
+
def db_restore_cmd file_to_restore
|
72
|
+
username, password, database, adapter = db_config
|
73
|
+
db_restore_mysql_cmd(username, password, database, file_to_restore)
|
74
|
+
end
|
75
|
+
|
76
|
+
def db_create_database_cmd
|
77
|
+
username, password, database, adapter = db_config
|
78
|
+
db_create_database_mysql_cmd(username, password, database)
|
79
|
+
end
|
80
|
+
|
81
|
+
namespace :db do
|
82
|
+
namespace :local do
|
83
|
+
|
84
|
+
desc "Simply calls local backup"
|
85
|
+
task :default do
|
86
|
+
db.local.backup
|
87
|
+
end
|
88
|
+
|
89
|
+
desc "Runs a local db backup"
|
90
|
+
task :backup, :roles => :db, :only => { :primary => true } do
|
91
|
+
run_locally db_backup_cmd File.join(db_backup_path, db_backup_filename)
|
92
|
+
end
|
93
|
+
|
94
|
+
desc "Restores the DB based on the last updated file in the db backup local dir"
|
95
|
+
task :restore, :roles => :db, :only => { :primary => true } do
|
96
|
+
file_to_restore = run_locally("ls -xt #{db_backup_local_dir}/#{db_backup_filename_base}*").split.take(1).first
|
97
|
+
run_locally db_restore_cmd file_to_restore unless file_to_restore.nil?
|
98
|
+
end
|
99
|
+
|
100
|
+
desc "Locally purges old backups"
|
101
|
+
task :cleanup, :roles => :db, :only => { :primary => true } do
|
102
|
+
files_to_remove = run_locally("ls -xt #{db_backup_local_dir}/#{db_backup_filename_base}*").split.drop(db_backup_count.to_i).join(" ")
|
103
|
+
run_locally "rm #{files_to_remove}" unless files_to_remove.nil? or files_to_remove.length == 0
|
104
|
+
end
|
105
|
+
|
106
|
+
desc "Syncs local database with remote database"
|
107
|
+
task :sync, :roles => :db, :only => { :primary => true } do
|
108
|
+
db.remote.download
|
109
|
+
db.local.restore
|
110
|
+
end
|
111
|
+
|
112
|
+
desc "Creates local backup dir"
|
113
|
+
task :setup, :roles => :db, :only => { :primary => true } do
|
114
|
+
run_locally "mkdir -p #{db_backup_local_dir}"
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
118
|
+
namespace :remote do
|
119
|
+
desc "Simply calls remote backup"
|
120
|
+
task :default do
|
121
|
+
db.remote.backup
|
122
|
+
end
|
123
|
+
|
124
|
+
task :create_database, :roles => :db do
|
125
|
+
username, password, database, adapter = db_config
|
126
|
+
run db_create_database_cmd
|
127
|
+
end
|
128
|
+
|
129
|
+
desc "Backs up the remote DB"
|
130
|
+
task :backup, :roles => :db, :only => { :primary => true } do
|
131
|
+
run db_backup_cmd File.join(db_backup_path, db_backup_filename)
|
132
|
+
end
|
133
|
+
|
134
|
+
desc "Restores the remote DB based on the last updated file in remote db backups dir"
|
135
|
+
task :restore, :roles => :db, :only => { :primary => true } do
|
136
|
+
file_to_restore = capture("ls -xt #{db_backup_path}/#{db_backup_filename_base}*").split.take(1).first
|
137
|
+
run db_restore_cmd file_to_restore unless file_to_restore.nil?
|
138
|
+
end
|
139
|
+
|
140
|
+
desc "Downloads the current db into the local backup dir (also remotely backs up the DB)"
|
141
|
+
task :download, :roles => :db, :only => { :primary => true } do
|
142
|
+
run db_backup_cmd File.join(db_backup_path, db_backup_filename)
|
143
|
+
get File.join(db_backup_path, db_backup_filename), File.join(db_backup_local_dir, db_backup_filename)
|
144
|
+
end
|
145
|
+
|
146
|
+
desc "Uploads the DB dumps in local backup dir"
|
147
|
+
task :upload, :roles => :db, :only => { :primary => true } do
|
148
|
+
file_to_upload = run_locally("ls -xt #{db_backup_local_dir} | head -n 1").strip.chomp
|
149
|
+
put File.read(File.join Dir.getwd, db_backup_local_dir, file_to_upload), File.join(db_backup_path, file_to_upload) unless file_to_upload.nil? or file_to_upload.length == 0
|
150
|
+
end
|
151
|
+
|
152
|
+
desc "Creates a local db backup and syncs remote with the backup"
|
153
|
+
task :sync, :roles => :db, :only => { :primary => true } do
|
154
|
+
db.local.backup
|
155
|
+
db.remote.upload
|
156
|
+
db.remote.restore
|
157
|
+
end
|
158
|
+
|
159
|
+
desc "Purges old backup files"
|
160
|
+
task :cleanup, :roles => :db, :only => { :primary => true } do
|
161
|
+
files_to_remove = capture("ls -xt #{db_backup_path}/#{db_backup_filename_base}*").split.drop(db_backup_count.to_i).join(" ")
|
162
|
+
run "#{try_sudo} rm #{files_to_remove}" unless files_to_remove.nil? or files_to_remove.length == 0
|
163
|
+
end
|
164
|
+
|
165
|
+
desc "Creates the backup file"
|
166
|
+
task :setup, :roles => :db, :only => { :primary => true } do
|
167
|
+
run "#{try_sudo} mkdir -p #{db_backup_path}"
|
168
|
+
end
|
169
|
+
end
|
170
|
+
end
|
171
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
require 'quapistrano/helper'
|
2
|
+
|
3
|
+
Capistrano::Configuration.instance(true).load do
|
4
|
+
|
5
|
+
_cset :shared_folders, {
|
6
|
+
'uploads' => 'public/uploads'
|
7
|
+
}
|
8
|
+
|
9
|
+
after 'deploy:setup' do
|
10
|
+
shared.remote.setup
|
11
|
+
end
|
12
|
+
|
13
|
+
after 'deploy:update' do
|
14
|
+
shared.remote.symlink
|
15
|
+
end
|
16
|
+
|
17
|
+
namespace :shared do
|
18
|
+
namespace :remote do
|
19
|
+
|
20
|
+
desc "Creates the shared folders under shared_path' "
|
21
|
+
task :setup, :roles => :app, :except => { :no_release => true } do
|
22
|
+
run shared_folders.map { |from, _| "#{try_sudo} mkdir -p #{shared_path}/#{from}" }.join( ' && ')
|
23
|
+
end
|
24
|
+
|
25
|
+
desc "Creates the symlink between the shared folders and the release path"
|
26
|
+
task :symlink, :roles => :app, :except => { :no_release => true } do
|
27
|
+
run shared_folders.map { |from, to| "#{try_sudo} ln -is #{shared_path}/#{from} #{current_path}/#{to}" }.join(' && ')
|
28
|
+
end
|
29
|
+
|
30
|
+
desc "Syncs the remote shared folders with the local ones"
|
31
|
+
task :sync, :roles => :app, :except => { :no_release => true } do
|
32
|
+
run_locally shared_folders.map { |from, to| roles[:app].map { |role| "rsync -vr --exclude='.DS_Store' #{File.expand_path(to)} #{user}@#{role}:#{File.expand_path(File.join(shared_path,from, '..'))}" }.join(' && ') }.join(' && ')
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
namespace :local do
|
37
|
+
desc "Syncs the local shared folders with the remote ones"
|
38
|
+
task :sync, :roles => :app, :except => { :no_release => true } do
|
39
|
+
run_locally shared_folders.map { |from, to| "rsync -vr --exclude='.DS_Store' #{user}@#{roles[:app].to_ary.first}:#{shared_path}/#{from} #{File.expand_path(File.join(to, '..'))}" }.join(' && ')
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
@@ -0,0 +1,88 @@
|
|
1
|
+
require 'quapistrano/helper'
|
2
|
+
|
3
|
+
Capistrano::Configuration.instance(true).load do
|
4
|
+
_cset :rails_env, "production"
|
5
|
+
|
6
|
+
_cset :unicorn_bin, "#{try_bundle} unicorn_rails"
|
7
|
+
_cset :unicorn_config, "config/unicorn.rb"
|
8
|
+
|
9
|
+
_cset :pid_dir, "#{shared_dir}/pids"
|
10
|
+
_cset :socket_dir, "#{shared_dir}/sockets"
|
11
|
+
|
12
|
+
_cset (:pids_path) { File.join(deploy_to, pid_dir) }
|
13
|
+
_cset (:sockets_path) { File.join(deploy_to, socket_dir) }
|
14
|
+
|
15
|
+
_cset (:unicorn_socket) { File.join(sockets_path, 'unicorn.sock') }
|
16
|
+
_cset (:unicorn_pid) { File.join(pids_path, 'unicorn.pid') }
|
17
|
+
|
18
|
+
|
19
|
+
after 'deploy:setup' do
|
20
|
+
unicorn.setup
|
21
|
+
end
|
22
|
+
|
23
|
+
namespace :deploy do
|
24
|
+
task :restart do
|
25
|
+
unicorn.restart
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
|
30
|
+
def unicorn_start_cmd
|
31
|
+
"cd #{current_path} && #{unicorn_bin} -c #{unicorn_config} -E #{rails_env} -D"
|
32
|
+
end
|
33
|
+
|
34
|
+
def unicorn_stop_cmd
|
35
|
+
"cd #{current_path} && kill -QUIT `cat #{unicorn_pid}`"
|
36
|
+
end
|
37
|
+
|
38
|
+
def unicorn_reload_cmd
|
39
|
+
"cd #{current_path} && kill -USR2 `cat #{unicorn_pid}`"
|
40
|
+
end
|
41
|
+
|
42
|
+
def unicorn_status_cmd
|
43
|
+
"if [ -f #{unicorn_pid} ]; then ps -Afu #{user} | grep `cat #{unicorn_pid}` | grep -v grep; fi"
|
44
|
+
end
|
45
|
+
|
46
|
+
def unicorn_setup_cmd
|
47
|
+
join_cmds "mkdir -p #{sockets_path}", "chown -R #{user} #{sockets_path}", "chmod +rw #{sockets_path}"
|
48
|
+
end
|
49
|
+
|
50
|
+
def unicorn_restart_cmd
|
51
|
+
join_cmds unicorn_stop_cmd, unicorn_start_cmd
|
52
|
+
end
|
53
|
+
|
54
|
+
namespace :unicorn do
|
55
|
+
desc "Starts an unicorn daemon using provided unicorn's configuration file and rails environment"
|
56
|
+
task :start, :roles => :app do
|
57
|
+
run unicorn_start_cmd
|
58
|
+
end
|
59
|
+
|
60
|
+
desc "Stops the unicorn daemon pointed by the pid file"
|
61
|
+
task :stop, :roles => :app do
|
62
|
+
run unicorn_stop_cmd
|
63
|
+
end
|
64
|
+
|
65
|
+
desc "Makes unicorn reload the rails application"
|
66
|
+
task :reload, :roles => :app do
|
67
|
+
run unicorn_reload_cmd
|
68
|
+
end
|
69
|
+
|
70
|
+
desc "Restarts unicorn daemon so that new updates are reflected"
|
71
|
+
task :restart, :roles => :app do
|
72
|
+
run unicorn_restart_cmd
|
73
|
+
end
|
74
|
+
|
75
|
+
desc "List the unicorn processes running"
|
76
|
+
task :status, :roles => :app do
|
77
|
+
text = []
|
78
|
+
run unicorn_status_cmd { |_,_,data| text << data }
|
79
|
+
text.join('').lines.each { |line| logger.info(line) }
|
80
|
+
end
|
81
|
+
|
82
|
+
desc "Creates a folder to place the socket file"
|
83
|
+
task :setup, :roles => :app do
|
84
|
+
run unicorn_setup_cmd
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
module Helpers
|
2
|
+
module Common
|
3
|
+
def say msg
|
4
|
+
Capistrano::CLI.ui.say(msg)
|
5
|
+
end
|
6
|
+
|
7
|
+
def join_cmds *cmds
|
8
|
+
cmds.join(' && ')
|
9
|
+
end
|
10
|
+
|
11
|
+
def _cset(variable, *args, &block)
|
12
|
+
set(variable, *args, &block) unless exists?(variable)
|
13
|
+
end
|
14
|
+
|
15
|
+
def try_bundle
|
16
|
+
defined?(Bundler) ? "bundle exec" : ""
|
17
|
+
end
|
18
|
+
|
19
|
+
def is_using_nginx
|
20
|
+
is_using('nginx',:web_server)
|
21
|
+
end
|
22
|
+
|
23
|
+
def is_using_unicorn
|
24
|
+
is_using('unicorn',:app_server)
|
25
|
+
end
|
26
|
+
|
27
|
+
def is_using(something, with_some_var)
|
28
|
+
exists?(with_some_var.to_sym) && fetch(with_some_var.to_sym).to_s.downcase == something
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
metadata
ADDED
@@ -0,0 +1,118 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: quapistrano
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.0.0
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Tiago Melo
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2012-04-09 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: capistrano
|
16
|
+
requirement: &70318358998160 !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ! '>='
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: '0'
|
22
|
+
type: :runtime
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: *70318358998160
|
25
|
+
- !ruby/object:Gem::Dependency
|
26
|
+
name: bundler
|
27
|
+
requirement: &70318358997560 !ruby/object:Gem::Requirement
|
28
|
+
none: false
|
29
|
+
requirements:
|
30
|
+
- - ! '>='
|
31
|
+
- !ruby/object:Gem::Version
|
32
|
+
version: '0'
|
33
|
+
type: :development
|
34
|
+
prerelease: false
|
35
|
+
version_requirements: *70318358997560
|
36
|
+
- !ruby/object:Gem::Dependency
|
37
|
+
name: jeweler
|
38
|
+
requirement: &70318358996940 !ruby/object:Gem::Requirement
|
39
|
+
none: false
|
40
|
+
requirements:
|
41
|
+
- - ~>
|
42
|
+
- !ruby/object:Gem::Version
|
43
|
+
version: 1.8.3
|
44
|
+
type: :development
|
45
|
+
prerelease: false
|
46
|
+
version_requirements: *70318358996940
|
47
|
+
- !ruby/object:Gem::Dependency
|
48
|
+
name: rspec
|
49
|
+
requirement: &70318359012720 !ruby/object:Gem::Requirement
|
50
|
+
none: false
|
51
|
+
requirements:
|
52
|
+
- - ! '>='
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
type: :development
|
56
|
+
prerelease: false
|
57
|
+
version_requirements: *70318359012720
|
58
|
+
- !ruby/object:Gem::Dependency
|
59
|
+
name: capistrano
|
60
|
+
requirement: &70318359012060 !ruby/object:Gem::Requirement
|
61
|
+
none: false
|
62
|
+
requirements:
|
63
|
+
- - ! '>='
|
64
|
+
- !ruby/object:Gem::Version
|
65
|
+
version: '0'
|
66
|
+
type: :runtime
|
67
|
+
prerelease: false
|
68
|
+
version_requirements: *70318359012060
|
69
|
+
description: A 'Work in Progress' gem with several recipes for capistrano, using a
|
70
|
+
clean approach, delegating dawting tasks to provisioners
|
71
|
+
email: tiago.blackcode@gmail.com
|
72
|
+
executables: []
|
73
|
+
extensions: []
|
74
|
+
extra_rdoc_files:
|
75
|
+
- LICENSE.txt
|
76
|
+
- README.rdoc
|
77
|
+
files:
|
78
|
+
- .gitignore
|
79
|
+
- Gemfile
|
80
|
+
- Gemfile.lock
|
81
|
+
- LICENSE.txt
|
82
|
+
- README.rdoc
|
83
|
+
- Rakefile
|
84
|
+
- VERSION
|
85
|
+
- lib/quapistrano/helper.rb
|
86
|
+
- lib/quapistrano/recipes/db.rb
|
87
|
+
- lib/quapistrano/recipes/shared.rb
|
88
|
+
- lib/quapistrano/recipes/unicorn.rb
|
89
|
+
- lib/quapistrano/support/common.rb
|
90
|
+
homepage: http://github.com/tiagoblackcode/quapistrano
|
91
|
+
licenses:
|
92
|
+
- MIT
|
93
|
+
post_install_message:
|
94
|
+
rdoc_options: []
|
95
|
+
require_paths:
|
96
|
+
- lib
|
97
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
98
|
+
none: false
|
99
|
+
requirements:
|
100
|
+
- - ! '>='
|
101
|
+
- !ruby/object:Gem::Version
|
102
|
+
version: '0'
|
103
|
+
segments:
|
104
|
+
- 0
|
105
|
+
hash: -4298356924262818299
|
106
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
107
|
+
none: false
|
108
|
+
requirements:
|
109
|
+
- - ! '>='
|
110
|
+
- !ruby/object:Gem::Version
|
111
|
+
version: '0'
|
112
|
+
requirements: []
|
113
|
+
rubyforge_project:
|
114
|
+
rubygems_version: 1.8.11
|
115
|
+
signing_key:
|
116
|
+
specification_version: 3
|
117
|
+
summary: Yet another recipes gem for capistrano
|
118
|
+
test_files: []
|