capobvious 0.3.pre → 0.3.pre1
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.
- data/README.md +8 -0
- data/lib/capistrano/ext/capobvious.rb +3 -370
- data/lib/capobvious/recipes/assets.rb +1 -1
- data/lib/capobvious/recipes/db.rb +31 -32
- data/lib/capobvious/recipes/log.rb +9 -0
- data/lib/capobvious/recipes/main.rb +291 -0
- data/lib/capobvious/recipes/nginx.rb +85 -0
- data/lib/capobvious/recipes/unicorn.rb +24 -23
- data/lib/capobvious/version.rb +1 -1
- metadata +4 -1
data/README.md
CHANGED
@@ -83,6 +83,14 @@ require 'capobvious/recipes/bundle'
|
|
83
83
|
cap bundle:install # run automatically on deploy
|
84
84
|
```
|
85
85
|
|
86
|
+
### log
|
87
|
+
```ruby
|
88
|
+
require 'capobvious/recipes/log'
|
89
|
+
```
|
90
|
+
```sh
|
91
|
+
cap log:tail # stream production.log
|
92
|
+
```
|
93
|
+
|
86
94
|
## Contributing
|
87
95
|
|
88
96
|
1. Fork it
|
@@ -1,5 +1,6 @@
|
|
1
1
|
#$:.unshift(File.expand_path('./lib', ENV['rvm_path']))
|
2
2
|
require "rvm/capistrano"
|
3
|
+
require 'capobvious/recipes/main'
|
3
4
|
require 'capobvious/recipes/unicorn'
|
4
5
|
require 'capobvious/recipes/delayed_job'
|
5
6
|
require 'capobvious/recipes/sitemap_generator'
|
@@ -11,375 +12,7 @@ require 'capobvious/recipes/logrotate'
|
|
11
12
|
require 'capobvious/recipes/whenever'
|
12
13
|
require 'capobvious/recipes/rake'
|
13
14
|
require 'capobvious/recipes/import'
|
15
|
+
require 'capobvious/recipes/nginx'
|
16
|
+
require 'capobvious/recipes/log'
|
14
17
|
|
15
|
-
Capistrano::Configuration.instance(:must_exist).load do
|
16
|
-
_cset(:ruby_version) { RUBY_VERSION }
|
17
|
-
_cset :rvm_type, :user
|
18
|
-
_cset :rails_env, 'production'
|
19
|
-
_cset :branch, 'master'
|
20
|
-
_cset :deploy_via, :remote_cache
|
21
|
-
_cset :keep_releases, 5
|
22
|
-
_cset :use_sudo, false
|
23
|
-
_cset :scm, :git
|
24
|
-
_cset :del_backup, true
|
25
18
|
|
26
|
-
set :rvmrc_string ,"rvm use #{fetch(:ruby_version)}"
|
27
|
-
after "deploy:update_code", "create:rvmrc"
|
28
|
-
after "deploy:update", "deploy:cleanup"
|
29
|
-
|
30
|
-
#set :deploy_to, (exists?(:deploy_folder)? fetch(:deploy_folder) : "/home/#{user}/www/#{application}")
|
31
|
-
|
32
|
-
default_run_options[:pty] = true
|
33
|
-
ssh_options[:forward_agent] = true
|
34
|
-
|
35
|
-
|
36
|
-
def gem_use?(name)
|
37
|
-
gemfile_lock = File.read("Gemfile.lock")
|
38
|
-
return (gemfile_lock =~ /^\s*#{name}\s+\(/)? true : false
|
39
|
-
end
|
40
|
-
|
41
|
-
def which(name)
|
42
|
-
str = capture("which #{name}").chop
|
43
|
-
return false if str == ''
|
44
|
-
str
|
45
|
-
rescue
|
46
|
-
false
|
47
|
-
end
|
48
|
-
def local_which(name)
|
49
|
-
str = `which #{name}`.chop
|
50
|
-
return false if str == ''
|
51
|
-
str
|
52
|
-
rescue
|
53
|
-
false
|
54
|
-
end
|
55
|
-
def ssh_port
|
56
|
-
exists?(:port) ? fetch(:port) : 22
|
57
|
-
end
|
58
|
-
def local_gem_available?(name)
|
59
|
-
Gem::Specification.find_by_name(name)
|
60
|
-
rescue Gem::LoadError
|
61
|
-
false
|
62
|
-
rescue
|
63
|
-
Gem.available?(name)
|
64
|
-
end
|
65
|
-
|
66
|
-
|
67
|
-
def file_size(file_path)
|
68
|
-
size = run("wc -c #{file_path} | cut -d' ' -f1")
|
69
|
-
return size
|
70
|
-
end
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
VarGems = {'delayed_job' => :delayed_job, 'activerecord-postgres-hstore' => :hstore, 'sitemap_generator' => :sitemap_generator, 'whenever' => 'whenever'}
|
75
|
-
|
76
|
-
VarGems.each do |gem,var|
|
77
|
-
gem = gem.to_s
|
78
|
-
var = var.to_sym
|
79
|
-
if gem_use?(gem)
|
80
|
-
unless exists?(var)
|
81
|
-
logger.debug "gem '#{gem}' is found"
|
82
|
-
logger.important("#{var} set to true")
|
83
|
-
set var, true
|
84
|
-
end
|
85
|
-
end
|
86
|
-
end
|
87
|
-
|
88
|
-
namespace :create do
|
89
|
-
desc "Create .rvmrc"
|
90
|
-
task :rvmrc do
|
91
|
-
put rvmrc_string, "#{latest_release}/.rvmrc"
|
92
|
-
end
|
93
|
-
end
|
94
|
-
|
95
|
-
|
96
|
-
after "deploy:update_code", "auto:run"
|
97
|
-
namespace :auto do
|
98
|
-
task :run do
|
99
|
-
if exists?(:auto_migrate) && fetch(:auto_migrate) == true
|
100
|
-
db.migrate
|
101
|
-
end
|
102
|
-
if exists?(:sitemap_generator) && fetch(:sitemap_generator) == true
|
103
|
-
sitemap_generator.refresh
|
104
|
-
end
|
105
|
-
if exists?(:delayed_job) && fetch(:delayed_job) == true
|
106
|
-
delayed_job.restart
|
107
|
-
end
|
108
|
-
|
109
|
-
|
110
|
-
end
|
111
|
-
task :prepare do
|
112
|
-
db.create
|
113
|
-
nginx.conf
|
114
|
-
end
|
115
|
-
|
116
|
-
task :runtask do
|
117
|
-
path = "#{latest_release}/script/autorun.task"
|
118
|
-
if remote_file_exists?(path)
|
119
|
-
logger.important "Launching autorun commands"
|
120
|
-
cmds = capture("cat #{path}").split("\n").map(&:strip).map{|cmd| "RAILS_ENV=#{rails_env} #{cmd}" }
|
121
|
-
puts "cd #{latest_release} && #{cmds.join(' && ')}"
|
122
|
-
else
|
123
|
-
logger.important "autorun script not found"
|
124
|
-
end
|
125
|
-
end
|
126
|
-
end
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
namespace :export do
|
133
|
-
end
|
134
|
-
|
135
|
-
namespace :restore do
|
136
|
-
task :sys do
|
137
|
-
result = {}
|
138
|
-
i = 0
|
139
|
-
Dir.foreach(local_folder_path) do |d|
|
140
|
-
regexp = Regexp.new("\d+?(\.#{archive_ext})")
|
141
|
-
if d.include?(sys_file_name.gsub(regexp,""))
|
142
|
-
result[i.to_s] = d
|
143
|
-
i+=1
|
144
|
-
end
|
145
|
-
end
|
146
|
-
result.each{|key,value| puts "#{key} - #{value} ##{Time.at(value.scan(/\d+/).first.to_i)} #{File.size(local_folder_path+'/'+value)}"}
|
147
|
-
puts "WARNING: IT WILL OVERWRITE public/system FOLDER!"
|
148
|
-
select = Capistrano::CLI.ui.ask "select : "
|
149
|
-
file = result[select]
|
150
|
-
unless file.nil?
|
151
|
-
puts "You selected #{file}"
|
152
|
-
upload("#{local_folder_path}/#{file}","#{shared_path}/#{file}")
|
153
|
-
run "rm -rfv #{shared_path}/system/*"
|
154
|
-
run "#{arch_extract} #{shared_path}/#{file} -o#{shared_path}"
|
155
|
-
run "chmod -R o=rX #{shared_path}/system"
|
156
|
-
run "rm -v #{shared_path}/#{file}"
|
157
|
-
end
|
158
|
-
end
|
159
|
-
end
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
namespace :nginx do
|
165
|
-
[:stop, :start, :restart, :reload].each do |action|
|
166
|
-
desc "#{action.to_s} nginx"
|
167
|
-
task action, :roles => :web do
|
168
|
-
run "#{sudo} /etc/init.d/nginx #{action.to_s}"
|
169
|
-
end
|
170
|
-
end
|
171
|
-
|
172
|
-
desc "Add app nginx conf to server"
|
173
|
-
task :conf do
|
174
|
-
default_nginx_template = <<-EOF
|
175
|
-
server {
|
176
|
-
listen 80;
|
177
|
-
server_name #{server_name};
|
178
|
-
root #{current_path}/public;
|
179
|
-
|
180
|
-
# access_log #{shared_path}/log/nginx.access_log;# buffer=32k;
|
181
|
-
# error_log #{shared_path}/log/nginx.error_log error;
|
182
|
-
|
183
|
-
# location ~ ^/assets/ {
|
184
|
-
# expires 1y;
|
185
|
-
# add_header Cache-Control public;
|
186
|
-
# add_header ETag "";
|
187
|
-
# break;
|
188
|
-
# }
|
189
|
-
#{exists?(:nginx_add)? fetch(:nginx_add) : ""}
|
190
|
-
|
191
|
-
location ~ ^/(assets)/ {
|
192
|
-
root #{current_path}/public;
|
193
|
-
gzip_static on; # to serve pre-gzipped version
|
194
|
-
expires max;
|
195
|
-
add_header Cache-Control public;
|
196
|
-
}
|
197
|
-
|
198
|
-
location / {
|
199
|
-
try_files $uri @unicorn;
|
200
|
-
}
|
201
|
-
location @unicorn {
|
202
|
-
proxy_set_header Client-Ip $remote_addr;
|
203
|
-
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
204
|
-
proxy_set_header Host $host;
|
205
|
-
proxy_pass http://unix:#{shared_path}/pids/unicorn.sock;
|
206
|
-
}
|
207
|
-
}
|
208
|
-
EOF
|
209
|
-
if exists?(:server_redirect)
|
210
|
-
server_redirect = fetch(:server_redirect)#.split(" ")
|
211
|
-
redirect_template = <<-RED
|
212
|
-
server {
|
213
|
-
server_name #{server_redirect};
|
214
|
-
rewrite ^(.*)$ http://#{server_name.split(' ').first}$1 permanent;
|
215
|
-
}
|
216
|
-
RED
|
217
|
-
default_nginx_template += redirect_template
|
218
|
-
end
|
219
|
-
|
220
|
-
puts default_nginx_template
|
221
|
-
|
222
|
-
if exists?(:server_name)
|
223
|
-
#location = fetch(:template_dir, "config") + '/nginx.conf.erb'
|
224
|
-
#template = File.file?(location) ? File.read(location) : default_nginx_template
|
225
|
-
config = ERB.new(default_nginx_template)
|
226
|
-
# puts config.result
|
227
|
-
put config.result(binding), "#{shared_path}/nginx.conf"
|
228
|
-
run "#{sudo} ln -sfv #{shared_path}/nginx.conf /etc/nginx/sites-enabled/#{application}"
|
229
|
-
else
|
230
|
-
puts "Aborting because :server_name is not setted in deploy.rb"
|
231
|
-
end
|
232
|
-
end
|
233
|
-
desc "Del nginx config"
|
234
|
-
task :delconf do
|
235
|
-
run "#{sudo} rm -v /etc/nginx/sites-enabled/#{application}"
|
236
|
-
end
|
237
|
-
end
|
238
|
-
after "nginx:conf", "nginx:reload"
|
239
|
-
after "nginx:delconf", "nginx:reload"
|
240
|
-
|
241
|
-
|
242
|
-
|
243
|
-
namespace :log do
|
244
|
-
desc "tail -f production.log"
|
245
|
-
task :tail do
|
246
|
-
stream("tail -f -n 0 #{current_path}/log/production.log")
|
247
|
-
end
|
248
|
-
end
|
249
|
-
|
250
|
-
|
251
|
-
|
252
|
-
|
253
|
-
namespace :install do
|
254
|
-
desc "Install apt-nyaa"
|
255
|
-
task :aptnyaa do
|
256
|
-
run "#{sudo} apt-get --assume-yes install wget > /dev/null 2>&1 && cd /usr/bin/ && #{sudo} wget -Nq https://raw.github.com/nyaa/UbuntuScript/master/apt-nyaa && #{sudo} chmod +x apt-nyaa"
|
257
|
-
end
|
258
|
-
task :p7zip do
|
259
|
-
run "#{sudo} apt-get --assume-yes install p7zip-full"
|
260
|
-
end
|
261
|
-
desc "cap install:shmmax MAX=1024 (MB)"
|
262
|
-
task :shmmax do
|
263
|
-
if ENV.has_key?('MAX')
|
264
|
-
bits = ENV['MAX'].to_i*1024*1024
|
265
|
-
puts "setting shmmax to #{bits}"
|
266
|
-
run "#{sudo} sysctl -w kernel.shmmax=#{bits}"
|
267
|
-
run "echo 'kernel.shmmax=#{bits}' | #{sudo} tee -a /etc/sysctl.conf"
|
268
|
-
else
|
269
|
-
puts "Please run with MAX="
|
270
|
-
end
|
271
|
-
end
|
272
|
-
end
|
273
|
-
|
274
|
-
after 'deploy:update_code', 'sphinx:symlink' if exists?(:sphinx) && fetch(:sphinx)
|
275
|
-
namespace :sphinx do
|
276
|
-
desc "Rebuild indexes"
|
277
|
-
task :rebuild, :roles => :app, :except => {:no_release => true} do
|
278
|
-
run "cd #{latest_release} && bundle exec rake RAILS_ENV=#{rails_env} ts:rebuild"
|
279
|
-
end
|
280
|
-
desc "Reindex"
|
281
|
-
task :reindex, :roles => :app, :except => {:no_release => true} do
|
282
|
-
run "cd #{latest_release} && bundle exec rake RAILS_ENV=#{rails_env} ts:reindex"
|
283
|
-
end
|
284
|
-
desc "Sphinx start"
|
285
|
-
task :start, :roles => :app, :except => {:no_release => true} do
|
286
|
-
run "cd #{latest_release} && bundle exec rake RAILS_ENV=#{rails_env} ts:start"
|
287
|
-
end
|
288
|
-
desc "Sphinx stop"
|
289
|
-
task :stop, :roles => :app, :except => {:no_release => true} do
|
290
|
-
run "cd #{latest_release} && bundle exec rake RAILS_ENV=#{rails_env} ts:stop"
|
291
|
-
end
|
292
|
-
desc "Sphinx configure"
|
293
|
-
task :stop, :roles => :app, :except => {:no_release => true} do
|
294
|
-
run "cd #{latest_release} && bundle exec rake RAILS_ENV=#{rails_env} ts:conf"
|
295
|
-
end
|
296
|
-
desc "Re-establish symlinks"
|
297
|
-
task :symlink do
|
298
|
-
run "mkdir -pv #{shared_path}/sphinx"
|
299
|
-
run "rm -rf #{release_path}/db/sphinx && ln -sfv #{shared_path}/sphinx #{release_path}/db/sphinx"
|
300
|
-
run "ln -sfv #{shared_path}/sphinx/#{rails_env}.sphinx.conf #{release_path}/config/#{rails_env}.sphinx.conf"
|
301
|
-
end
|
302
|
-
end
|
303
|
-
|
304
|
-
|
305
|
-
|
306
|
-
namespace :runit do
|
307
|
-
[:stop, :start, :restart, :reload].each do |action|
|
308
|
-
desc "#{action.to_s} runit"
|
309
|
-
task action, :roles => :web do
|
310
|
-
run "#{sudo} sv #{action.to_s} #{application}"
|
311
|
-
end
|
312
|
-
end
|
313
|
-
|
314
|
-
desc "init"
|
315
|
-
task :init, :roles => :web do
|
316
|
-
join_ruby = ruby_version[/\d.\d.\d/].delete('.')
|
317
|
-
local_runit_path = "#{shared_path}/runit_temp"
|
318
|
-
runit = "/etc/sv/#{application}"
|
319
|
-
runit_path = "/etc/service/#{application}"
|
320
|
-
wrapper = "#{join_ruby}_unicorn"
|
321
|
-
logger.important('Creating unicorn wrapper', 'runit')
|
322
|
-
run "rvm wrapper #{ruby_version} #{join_ruby} unicorn"
|
323
|
-
|
324
|
-
runit_run = <<EOF
|
325
|
-
#!/bin/sh
|
326
|
-
exec 2>&1
|
327
|
-
export USER=#{user}
|
328
|
-
export HOME=/home/$USER
|
329
|
-
export RAILS_ENV=#{rails_env}
|
330
|
-
UNICORN="/home/#{user}/.rvm/bin/#{wrapper}"
|
331
|
-
UNICORN_CONF=#{unicorn_conf}
|
332
|
-
cd #{current_path}
|
333
|
-
exec chpst -u $USER:$USER $UNICORN -c $UNICORN_CONF
|
334
|
-
EOF
|
335
|
-
log_run = <<EOF
|
336
|
-
#!/bin/bash
|
337
|
-
LOG_FOLDER=/var/log/#{application}
|
338
|
-
mkdir -p $LOG_FOLDER
|
339
|
-
exec svlogd -tt $LOG_FOLDER
|
340
|
-
EOF
|
341
|
-
|
342
|
-
logger.important('Creating local runit path', 'runit')
|
343
|
-
run "mkdir -p #{local_runit_path}/log"
|
344
|
-
logger.important('Creating run script', 'runit')
|
345
|
-
put runit_run, "#{local_runit_path}/run"
|
346
|
-
run "chmod +x #{local_runit_path}/run"
|
347
|
-
logger.important('Creating log script', 'runit')
|
348
|
-
put log_run, "#{local_runit_path}/log/run"
|
349
|
-
run "chmod +x #{local_runit_path}/log/run"
|
350
|
-
|
351
|
-
run "#{sudo} mv #{local_runit_path} #{runit} && #{sudo} ln -s #{runit} #{runit_path}"
|
352
|
-
run "#{sudo} chown -R root:root #{runit}"
|
353
|
-
|
354
|
-
#logger.important('Creating symlink', 'runit')
|
355
|
-
#symlink = "#{sudo} ln -s #{local_runit_path} #{runit_path}"
|
356
|
-
#run symlink
|
357
|
-
|
358
|
-
#puts "$ cat #{runit_path}/run"
|
359
|
-
#puts run
|
360
|
-
end
|
361
|
-
end
|
362
|
-
|
363
|
-
|
364
|
-
|
365
|
-
# Check if remote file exists
|
366
|
-
#
|
367
|
-
def remote_file_exists?(full_path)
|
368
|
-
'true' == capture("if [ -e #{full_path} ]; then echo 'true'; fi").strip
|
369
|
-
end
|
370
|
-
|
371
|
-
# Check if process is running
|
372
|
-
#
|
373
|
-
def remote_process_exists?(pid_file)
|
374
|
-
capture("ps -p $(cat #{pid_file}) ; true").strip.split("\n").size == 2
|
375
|
-
end
|
376
|
-
|
377
|
-
|
378
|
-
namespace :deploy do
|
379
|
-
task :restart do
|
380
|
-
unicorn.restart
|
381
|
-
end
|
382
|
-
end
|
383
|
-
|
384
|
-
|
385
|
-
end
|
@@ -1,46 +1,45 @@
|
|
1
1
|
Capistrano::Configuration.instance(:must_exist).load do
|
2
|
+
def database_yml(env = rails_env)
|
3
|
+
yml = File.read(fetch(:database_yml_path))
|
4
|
+
config = YAML::load(yml)[env.to_s]
|
5
|
+
config.keys.each do |key|
|
6
|
+
config[(key.to_sym rescue key) || key] = config.delete(key)
|
7
|
+
end
|
8
|
+
config
|
9
|
+
end
|
10
|
+
|
2
11
|
psql = "psql -h localhost"
|
3
12
|
psql_postgres = "#{psql} -U postgres"
|
4
13
|
|
5
|
-
|
14
|
+
#adapter = config[fetch(:rails_env)]["adapter"]
|
15
|
+
#set :database, config[fetch(:rails_env)]["database"]
|
16
|
+
#db_username = config[fetch(:rails_env)]["username"]
|
17
|
+
#db_password = config[fetch(:rails_env)]["password"]
|
6
18
|
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
#end
|
13
|
-
if database_yml
|
14
|
-
config = YAML::load(database_yml)
|
15
|
-
adapter = config[rails_env]["adapter"]
|
16
|
-
database = config[rails_env]["database"]
|
17
|
-
db_username = config[rails_env]["username"]
|
18
|
-
db_password = config[rails_env]["password"]
|
19
|
-
|
20
|
-
local_rails_env = 'development'
|
21
|
-
local_adapter = config[local_rails_env]["adapter"]
|
22
|
-
local_database = config[local_rails_env]["database"]
|
23
|
-
local_db_username = config[local_rails_env]["username"]||`whoami`.chop
|
24
|
-
local_db_password = config[local_rails_env]["password"]
|
25
|
-
end
|
19
|
+
#local_rails_env = 'development'
|
20
|
+
#local_adapter = config[local_rails_env]["adapter"]
|
21
|
+
#local_database = config[local_rails_env]["database"]
|
22
|
+
#local_db_username = config[local_rails_env]["username"]||`whoami`.chop
|
23
|
+
#local_db_password = config[local_rails_env]["password"]
|
26
24
|
|
27
|
-
set :local_folder_path, "tmp/backup"
|
28
25
|
set :timestamp, Time.new.to_i.to_s
|
29
26
|
set :db_archive_ext, "tar.bz2"
|
30
27
|
set :arch_extract, "tar -xvjf"
|
31
28
|
set :arch_create, "tar -cvjf"
|
32
29
|
|
33
|
-
set :db_file_name, "#{
|
30
|
+
set :db_file_name, "#{fetch(:application)}-#{timestamp}.sql"
|
34
31
|
set :sys_file_name, "#{application}-system-#{timestamp}.#{db_archive_ext}"
|
35
32
|
|
36
33
|
namespace :db do
|
37
34
|
task :create do
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
35
|
+
yml = database_yml
|
36
|
+
if yml[:adapter] == "postgresql"
|
37
|
+
sql = %|create user #{yml[:username]} with password '#{yml[:password]}';|
|
38
|
+
sql+= %|create database #{yml[:database]} owner #{yml[:username]};|
|
39
|
+
run "echo \"#{sql}\" | #{sudo} -u postgres psql"
|
40
|
+
run "echo \"CREATE EXTENSION IF NOT EXISTS hstore;\" | #{sudo} -u postgres psql #{yml[:database]}" if exists?(:hstore) && fetch(:hstore) == true
|
42
41
|
else
|
43
|
-
puts "Cannot create, adapter #{adapter} is not implemented yet"
|
42
|
+
puts "Cannot create, adapter #{yml[:adapter]} is not implemented yet"
|
44
43
|
end
|
45
44
|
end
|
46
45
|
|
@@ -56,14 +55,14 @@ Capistrano::Configuration.instance(:must_exist).load do
|
|
56
55
|
|
57
56
|
task :import do
|
58
57
|
file_name = "#{db_file_name}.#{db_archive_ext}"
|
59
|
-
file_path = "#{
|
60
|
-
system "cd #{
|
58
|
+
file_path = "#{backup_folder_path}/#{file_name}"
|
59
|
+
system "cd #{backup_folder_path} && #{arch_extract} #{file_name}"
|
61
60
|
system "echo \"drop database IF EXISTS #{local_database}\" | #{psql_postgres}"
|
62
61
|
system "echo \"create database #{local_database} owner #{local_db_username};\" | #{psql_postgres}"
|
63
|
-
# system "#{psql_postgre} #{local_database} < #{
|
62
|
+
# system "#{psql_postgre} #{local_database} < #{backup_folder_path}/#{db_file_name}"
|
64
63
|
puts "ENTER your development password: #{local_db_password}"
|
65
|
-
system "#{psql} -U#{local_db_username} #{local_database} < #{
|
66
|
-
system "rm #{
|
64
|
+
system "#{psql} -U#{local_db_username} #{local_database} < #{backup_folder_path}/#{db_file_name}"
|
65
|
+
system "rm #{backup_folder_path}/#{db_file_name}"
|
67
66
|
end
|
68
67
|
task :pg_import do
|
69
68
|
backup.db
|
@@ -0,0 +1,291 @@
|
|
1
|
+
Capistrano::Configuration.instance(:must_exist).load do
|
2
|
+
_cset(:ruby_version) { RUBY_VERSION }
|
3
|
+
_cset :rvm_type, :user
|
4
|
+
_cset :rails_env, 'production'
|
5
|
+
_cset :branch, 'master'
|
6
|
+
_cset :deploy_via, :remote_cache
|
7
|
+
_cset :keep_releases, 5
|
8
|
+
_cset :use_sudo, false
|
9
|
+
_cset :scm, :git
|
10
|
+
_cset :del_backup, true
|
11
|
+
_cset :backup_folder_path, "tmp/backup"
|
12
|
+
_cset :database_yml_path, 'config/database.yml'
|
13
|
+
|
14
|
+
set :rvmrc_string ,"rvm use #{fetch(:ruby_version)}"
|
15
|
+
after "deploy:update_code", "create:rvmrc"
|
16
|
+
after "deploy:update", "deploy:cleanup"
|
17
|
+
|
18
|
+
#set :deploy_to, (exists?(:deploy_folder)? fetch(:deploy_folder) : "/home/#{user}/www/#{application}")
|
19
|
+
|
20
|
+
default_run_options[:pty] = true
|
21
|
+
ssh_options[:forward_agent] = true
|
22
|
+
|
23
|
+
|
24
|
+
def gem_use?(name)
|
25
|
+
gemfile_lock = File.read("Gemfile.lock")
|
26
|
+
return (gemfile_lock =~ /^\s*#{name}\s+\(/)? true : false
|
27
|
+
end
|
28
|
+
|
29
|
+
def which(name)
|
30
|
+
str = capture("which #{name}").chop
|
31
|
+
return false if str == ''
|
32
|
+
str
|
33
|
+
rescue
|
34
|
+
false
|
35
|
+
end
|
36
|
+
def local_which(name)
|
37
|
+
str = `which #{name}`.chop
|
38
|
+
return false if str == ''
|
39
|
+
str
|
40
|
+
rescue
|
41
|
+
false
|
42
|
+
end
|
43
|
+
def ssh_port
|
44
|
+
exists?(:port) ? fetch(:port) : 22
|
45
|
+
end
|
46
|
+
def local_gem_available?(name)
|
47
|
+
Gem::Specification.find_by_name(name)
|
48
|
+
rescue Gem::LoadError
|
49
|
+
false
|
50
|
+
rescue
|
51
|
+
Gem.available?(name)
|
52
|
+
end
|
53
|
+
|
54
|
+
|
55
|
+
def file_size(file_path)
|
56
|
+
size = run("wc -c #{file_path} | cut -d' ' -f1")
|
57
|
+
return size
|
58
|
+
end
|
59
|
+
|
60
|
+
|
61
|
+
|
62
|
+
VarGems = {'delayed_job' => :delayed_job, 'activerecord-postgres-hstore' => :hstore, 'sitemap_generator' => :sitemap_generator, 'whenever' => 'whenever'}
|
63
|
+
|
64
|
+
VarGems.each do |gem,var|
|
65
|
+
gem = gem.to_s
|
66
|
+
var = var.to_sym
|
67
|
+
if gem_use?(gem)
|
68
|
+
unless exists?(var)
|
69
|
+
logger.debug "gem '#{gem}' is found"
|
70
|
+
logger.important("#{var} set to true")
|
71
|
+
set var, true
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
namespace :create do
|
77
|
+
desc "Create .rvmrc"
|
78
|
+
task :rvmrc do
|
79
|
+
put rvmrc_string, "#{latest_release}/.rvmrc"
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
|
84
|
+
after "bundle:install", "auto:run"
|
85
|
+
namespace :auto do
|
86
|
+
task :run do
|
87
|
+
if exists?(:auto_migrate) && fetch(:auto_migrate) == true
|
88
|
+
db.migrate
|
89
|
+
end
|
90
|
+
if exists?(:sitemap_generator) && fetch(:sitemap_generator) == true
|
91
|
+
sitemap_generator.refresh
|
92
|
+
end
|
93
|
+
if exists?(:delayed_job) && fetch(:delayed_job) == true
|
94
|
+
delayed_job.restart
|
95
|
+
end
|
96
|
+
|
97
|
+
|
98
|
+
end
|
99
|
+
task :prepare do
|
100
|
+
db.create
|
101
|
+
nginx.conf
|
102
|
+
end
|
103
|
+
|
104
|
+
task :runtask do
|
105
|
+
path = "#{latest_release}/script/autorun.task"
|
106
|
+
if remote_file_exists?(path)
|
107
|
+
logger.important "Launching autorun commands"
|
108
|
+
cmds = capture("cat #{path}").split("\n").map(&:strip).map{|cmd| "RAILS_ENV=#{rails_env} #{cmd}" }
|
109
|
+
puts "cd #{latest_release} && #{cmds.join(' && ')}"
|
110
|
+
else
|
111
|
+
logger.important "autorun script not found"
|
112
|
+
end
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
|
117
|
+
|
118
|
+
|
119
|
+
|
120
|
+
namespace :export do
|
121
|
+
end
|
122
|
+
|
123
|
+
namespace :restore do
|
124
|
+
task :sys do
|
125
|
+
result = {}
|
126
|
+
i = 0
|
127
|
+
Dir.foreach(local_folder_path) do |d|
|
128
|
+
regexp = Regexp.new("\d+?(\.#{archive_ext})")
|
129
|
+
if d.include?(sys_file_name.gsub(regexp,""))
|
130
|
+
result[i.to_s] = d
|
131
|
+
i+=1
|
132
|
+
end
|
133
|
+
end
|
134
|
+
result.each{|key,value| puts "#{key} - #{value} ##{Time.at(value.scan(/\d+/).first.to_i)} #{File.size(local_folder_path+'/'+value)}"}
|
135
|
+
puts "WARNING: IT WILL OVERWRITE public/system FOLDER!"
|
136
|
+
select = Capistrano::CLI.ui.ask "select : "
|
137
|
+
file = result[select]
|
138
|
+
unless file.nil?
|
139
|
+
puts "You selected #{file}"
|
140
|
+
upload("#{local_folder_path}/#{file}","#{shared_path}/#{file}")
|
141
|
+
run "rm -rfv #{shared_path}/system/*"
|
142
|
+
run "#{arch_extract} #{shared_path}/#{file} -o#{shared_path}"
|
143
|
+
run "chmod -R o=rX #{shared_path}/system"
|
144
|
+
run "rm -v #{shared_path}/#{file}"
|
145
|
+
end
|
146
|
+
end
|
147
|
+
end
|
148
|
+
|
149
|
+
|
150
|
+
|
151
|
+
|
152
|
+
|
153
|
+
|
154
|
+
|
155
|
+
|
156
|
+
|
157
|
+
|
158
|
+
|
159
|
+
namespace :install do
|
160
|
+
desc "Install apt-nyaa"
|
161
|
+
task :aptnyaa do
|
162
|
+
run "#{sudo} apt-get --assume-yes install wget > /dev/null 2>&1 && cd /usr/bin/ && #{sudo} wget -Nq https://raw.github.com/nyaa/UbuntuScript/master/apt-nyaa && #{sudo} chmod +x apt-nyaa"
|
163
|
+
end
|
164
|
+
task :p7zip do
|
165
|
+
run "#{sudo} apt-get --assume-yes install p7zip-full"
|
166
|
+
end
|
167
|
+
desc "cap install:shmmax MAX=1024 (MB)"
|
168
|
+
task :shmmax do
|
169
|
+
if ENV.has_key?('MAX')
|
170
|
+
bits = ENV['MAX'].to_i*1024*1024
|
171
|
+
puts "setting shmmax to #{bits}"
|
172
|
+
run "#{sudo} sysctl -w kernel.shmmax=#{bits}"
|
173
|
+
run "echo 'kernel.shmmax=#{bits}' | #{sudo} tee -a /etc/sysctl.conf"
|
174
|
+
else
|
175
|
+
puts "Please run with MAX="
|
176
|
+
end
|
177
|
+
end
|
178
|
+
end
|
179
|
+
|
180
|
+
after 'deploy:update_code', 'sphinx:symlink' if exists?(:sphinx) && fetch(:sphinx)
|
181
|
+
namespace :sphinx do
|
182
|
+
desc "Rebuild indexes"
|
183
|
+
task :rebuild, :roles => :app, :except => {:no_release => true} do
|
184
|
+
run "cd #{latest_release} && bundle exec rake RAILS_ENV=#{rails_env} ts:rebuild"
|
185
|
+
end
|
186
|
+
desc "Reindex"
|
187
|
+
task :reindex, :roles => :app, :except => {:no_release => true} do
|
188
|
+
run "cd #{latest_release} && bundle exec rake RAILS_ENV=#{rails_env} ts:reindex"
|
189
|
+
end
|
190
|
+
desc "Sphinx start"
|
191
|
+
task :start, :roles => :app, :except => {:no_release => true} do
|
192
|
+
run "cd #{latest_release} && bundle exec rake RAILS_ENV=#{rails_env} ts:start"
|
193
|
+
end
|
194
|
+
desc "Sphinx stop"
|
195
|
+
task :stop, :roles => :app, :except => {:no_release => true} do
|
196
|
+
run "cd #{latest_release} && bundle exec rake RAILS_ENV=#{rails_env} ts:stop"
|
197
|
+
end
|
198
|
+
desc "Sphinx configure"
|
199
|
+
task :stop, :roles => :app, :except => {:no_release => true} do
|
200
|
+
run "cd #{latest_release} && bundle exec rake RAILS_ENV=#{rails_env} ts:conf"
|
201
|
+
end
|
202
|
+
desc "Re-establish symlinks"
|
203
|
+
task :symlink do
|
204
|
+
run "mkdir -pv #{shared_path}/sphinx"
|
205
|
+
run "rm -rf #{release_path}/db/sphinx && ln -sfv #{shared_path}/sphinx #{release_path}/db/sphinx"
|
206
|
+
run "ln -sfv #{shared_path}/sphinx/#{rails_env}.sphinx.conf #{release_path}/config/#{rails_env}.sphinx.conf"
|
207
|
+
end
|
208
|
+
end
|
209
|
+
|
210
|
+
|
211
|
+
|
212
|
+
namespace :runit do
|
213
|
+
[:stop, :start, :restart, :reload].each do |action|
|
214
|
+
desc "#{action.to_s} runit"
|
215
|
+
task action, :roles => :web do
|
216
|
+
run "#{sudo} sv #{action.to_s} #{application}"
|
217
|
+
end
|
218
|
+
end
|
219
|
+
|
220
|
+
desc "init"
|
221
|
+
task :init, :roles => :web do
|
222
|
+
join_ruby = ruby_version[/\d.\d.\d/].delete('.')
|
223
|
+
local_runit_path = "#{shared_path}/runit_temp"
|
224
|
+
runit = "/etc/sv/#{application}"
|
225
|
+
runit_path = "/etc/service/#{application}"
|
226
|
+
wrapper = "#{join_ruby}_unicorn"
|
227
|
+
logger.important('Creating unicorn wrapper', 'runit')
|
228
|
+
run "rvm wrapper #{ruby_version} #{join_ruby} unicorn"
|
229
|
+
|
230
|
+
runit_run = <<EOF
|
231
|
+
#!/bin/sh
|
232
|
+
exec 2>&1
|
233
|
+
export USER=#{user}
|
234
|
+
export HOME=/home/$USER
|
235
|
+
export RAILS_ENV=#{rails_env}
|
236
|
+
UNICORN="/home/#{user}/.rvm/bin/#{wrapper}"
|
237
|
+
UNICORN_CONF=#{unicorn_conf}
|
238
|
+
cd #{current_path}
|
239
|
+
exec chpst -u $USER:$USER $UNICORN -c $UNICORN_CONF
|
240
|
+
EOF
|
241
|
+
log_run = <<EOF
|
242
|
+
#!/bin/bash
|
243
|
+
LOG_FOLDER=/var/log/#{application}
|
244
|
+
mkdir -p $LOG_FOLDER
|
245
|
+
exec svlogd -tt $LOG_FOLDER
|
246
|
+
EOF
|
247
|
+
|
248
|
+
logger.important('Creating local runit path', 'runit')
|
249
|
+
run "mkdir -p #{local_runit_path}/log"
|
250
|
+
logger.important('Creating run script', 'runit')
|
251
|
+
put runit_run, "#{local_runit_path}/run"
|
252
|
+
run "chmod +x #{local_runit_path}/run"
|
253
|
+
logger.important('Creating log script', 'runit')
|
254
|
+
put log_run, "#{local_runit_path}/log/run"
|
255
|
+
run "chmod +x #{local_runit_path}/log/run"
|
256
|
+
|
257
|
+
run "#{sudo} mv #{local_runit_path} #{runit} && #{sudo} ln -s #{runit} #{runit_path}"
|
258
|
+
run "#{sudo} chown -R root:root #{runit}"
|
259
|
+
|
260
|
+
#logger.important('Creating symlink', 'runit')
|
261
|
+
#symlink = "#{sudo} ln -s #{local_runit_path} #{runit_path}"
|
262
|
+
#run symlink
|
263
|
+
|
264
|
+
#puts "$ cat #{runit_path}/run"
|
265
|
+
#puts run
|
266
|
+
end
|
267
|
+
end
|
268
|
+
|
269
|
+
|
270
|
+
|
271
|
+
# Check if remote file exists
|
272
|
+
#
|
273
|
+
def remote_file_exists?(full_path)
|
274
|
+
'true' == capture("if [ -e #{full_path} ]; then echo 'true'; fi").strip
|
275
|
+
end
|
276
|
+
|
277
|
+
# Check if process is running
|
278
|
+
#
|
279
|
+
def remote_process_exists?(pid_file)
|
280
|
+
capture("ps -p $(cat #{pid_file}) ; true").strip.split("\n").size == 2
|
281
|
+
end
|
282
|
+
|
283
|
+
|
284
|
+
namespace :deploy do
|
285
|
+
task :restart do
|
286
|
+
unicorn.restart
|
287
|
+
end
|
288
|
+
end
|
289
|
+
|
290
|
+
|
291
|
+
end
|
@@ -0,0 +1,85 @@
|
|
1
|
+
Capistrano::Configuration.instance(:must_exist).load do
|
2
|
+
|
3
|
+
_cset(:nginx_config) { "#{application}-#{rails_env}" }
|
4
|
+
|
5
|
+
after "nginx:conf", "nginx:reload"
|
6
|
+
after "nginx:delconf", "nginx:reload"
|
7
|
+
namespace :nginx do
|
8
|
+
[:stop, :start, :restart, :reload].each do |action|
|
9
|
+
desc "#{action.to_s} nginx"
|
10
|
+
task action, :roles => :web do
|
11
|
+
run "#{sudo} /etc/init.d/nginx #{action.to_s}"
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
desc "Add app nginx conf to server"
|
16
|
+
task :conf do
|
17
|
+
assets_template = <<-EOF
|
18
|
+
location ~ ^/(assets)/ {
|
19
|
+
root #{current_path}/public;
|
20
|
+
gzip_static on; # to serve pre-gzipped version
|
21
|
+
expires max;
|
22
|
+
add_header Cache-Control public;
|
23
|
+
}
|
24
|
+
EOF
|
25
|
+
|
26
|
+
default_nginx_template = <<-EOF
|
27
|
+
server {
|
28
|
+
listen 80;
|
29
|
+
server_name #{server_name};
|
30
|
+
root #{current_path}/public;
|
31
|
+
|
32
|
+
# access_log #{shared_path}/log/nginx.access_log;# buffer=32k;
|
33
|
+
# error_log #{shared_path}/log/nginx.error_log error;
|
34
|
+
|
35
|
+
# location ~ ^/assets/ {
|
36
|
+
# expires 1y;
|
37
|
+
# add_header Cache-Control public;
|
38
|
+
# add_header ETag "";
|
39
|
+
# break;
|
40
|
+
# }
|
41
|
+
#{exists?(:nginx_add)? fetch(:nginx_add) : ""}
|
42
|
+
|
43
|
+
#{(exists?(:assets)&&fetch(:assets)==true)? assets_template : ''}
|
44
|
+
|
45
|
+
location / {
|
46
|
+
try_files $uri @unicorn;
|
47
|
+
}
|
48
|
+
location @unicorn {
|
49
|
+
proxy_set_header Client-Ip $remote_addr;
|
50
|
+
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
51
|
+
proxy_set_header Host $host;
|
52
|
+
proxy_pass http://unix:#{shared_path}/pids/unicorn.sock;
|
53
|
+
}
|
54
|
+
}
|
55
|
+
EOF
|
56
|
+
if exists?(:server_redirect)
|
57
|
+
server_redirect = fetch(:server_redirect)#.split(" ")
|
58
|
+
redirect_template = <<-RED
|
59
|
+
server {
|
60
|
+
server_name #{server_redirect};
|
61
|
+
rewrite ^(.*)$ http://#{server_name.split(' ').first}$1 permanent;
|
62
|
+
}
|
63
|
+
RED
|
64
|
+
default_nginx_template += redirect_template
|
65
|
+
end
|
66
|
+
|
67
|
+
puts default_nginx_template
|
68
|
+
|
69
|
+
if exists?(:server_name)
|
70
|
+
#location = fetch(:template_dir, "config") + '/nginx.conf.erb'
|
71
|
+
#template = File.file?(location) ? File.read(location) : default_nginx_template
|
72
|
+
config = ERB.new(default_nginx_template)
|
73
|
+
# puts config.result
|
74
|
+
put config.result(binding), "#{shared_path}/nginx.conf"
|
75
|
+
run "#{sudo} ln -sfv #{shared_path}/nginx.conf /etc/nginx/sites-enabled/#{fetch(:nginx_config)}"
|
76
|
+
else
|
77
|
+
abort "Aborting because :server_name is not setted in deploy.rb"
|
78
|
+
end
|
79
|
+
end
|
80
|
+
desc "Del nginx config"
|
81
|
+
task :delconf do
|
82
|
+
run "#{sudo} rm -v /etc/nginx/sites-enabled/#{fetch(:nginx_config)}"
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
@@ -1,29 +1,10 @@
|
|
1
1
|
Capistrano::Configuration.instance(:must_exist).load do
|
2
|
-
set :unicorn_init, "unicorn_#{fetch(:application)}"
|
3
|
-
set :unicorn_conf, "#{current_path}/config/unicorn.rb"
|
4
|
-
set :unicorn_pid, "#{shared_path}/pids/unicorn.pid"
|
5
2
|
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
#cd /home/rails/www/three-elements/current && sudo -u rails -H /home/rails/.rvm/bin/193_bundle exec /home/rails/.rvm/bin/193_unicorn -c /home/rails/www/three-elements/current/config/unicorn.rb -E production -D
|
10
|
-
join_ruby = ruby_version[/\d.\d.\d/].delete('.')
|
11
|
-
ruby_wrapper = "#{join_ruby}_unicorn"
|
12
|
-
ruby_wrapper_path = "/home/#{user}/.rvm/bin/#{ruby_wrapper}"
|
13
|
-
bundle_wrapper = "#{join_ruby}_bundle"
|
14
|
-
bundle_wrapper_path = "/home/#{user}/.rvm/bin/#{bundle_wrapper}"
|
15
|
-
|
16
|
-
run "rvm wrapper #{ruby_version} #{join_ruby} unicorn"
|
17
|
-
run "rvm wrapper #{ruby_version} #{join_ruby} bundle"
|
18
|
-
#puts "sudo -u #{user} -H /home/#{user}/.rvm/bin/#{wrapper} -c #{unicorn_conf} -E production -D"
|
19
|
-
command = "cd #{current_path} && sudo -u #{user} -H #{bundle_wrapper_path} exec #{ruby_wrapper_path} -c #{unicorn_conf} -E production -D"
|
20
|
-
puts command
|
21
|
-
|
22
|
-
run "#{sudo} sed -i 's/exit 0//g' /etc/rc.local"
|
23
|
-
run "echo \"#{command}\" | #{sudo} tee -a /etc/rc.local"
|
24
|
-
run "echo \"exit 0\" | #{sudo} tee -a /etc/rc.local"
|
25
|
-
end
|
3
|
+
_cset(:unicorn_init){ "unicorn_#{application}"}
|
4
|
+
_cset(:unicorn_conf) {"#{current_path}/config/unicorn.rb"}
|
5
|
+
_cset(:unicorn_pid){"#{shared_path}/pids/unicorn.pid"}
|
26
6
|
|
7
|
+
namespace :unicorn do
|
27
8
|
desc "start unicorn"
|
28
9
|
task :start do
|
29
10
|
if remote_file_exists?(unicorn_pid)
|
@@ -64,4 +45,24 @@ Capistrano::Configuration.instance(:must_exist).load do
|
|
64
45
|
end
|
65
46
|
end
|
66
47
|
|
48
|
+
desc "init autostart unicorn"
|
49
|
+
task :autostart do
|
50
|
+
#cd /home/rails/www/three-elements/current && sudo -u rails -H /home/rails/.rvm/bin/193_bundle exec /home/rails/.rvm/bin/193_unicorn -c /home/rails/www/three-elements/current/config/unicorn.rb -E production -D
|
51
|
+
join_ruby = ruby_version[/\d.\d.\d/].delete('.')
|
52
|
+
ruby_wrapper = "#{join_ruby}_unicorn"
|
53
|
+
ruby_wrapper_path = "/home/#{user}/.rvm/bin/#{ruby_wrapper}"
|
54
|
+
bundle_wrapper = "#{join_ruby}_bundle"
|
55
|
+
bundle_wrapper_path = "/home/#{user}/.rvm/bin/#{bundle_wrapper}"
|
56
|
+
|
57
|
+
run "rvm wrapper #{ruby_version} #{join_ruby} unicorn"
|
58
|
+
run "rvm wrapper #{ruby_version} #{join_ruby} bundle"
|
59
|
+
#puts "sudo -u #{user} -H /home/#{user}/.rvm/bin/#{wrapper} -c #{unicorn_conf} -E production -D"
|
60
|
+
command = "cd #{current_path} && sudo -u #{user} -H #{bundle_wrapper_path} exec #{ruby_wrapper_path} -c #{unicorn_conf} -E production -D"
|
61
|
+
puts command
|
62
|
+
|
63
|
+
run "#{sudo} sed -i 's/exit 0//g' /etc/rc.local"
|
64
|
+
run "echo \"#{command}\" | #{sudo} tee -a /etc/rc.local"
|
65
|
+
run "echo \"exit 0\" | #{sudo} tee -a /etc/rc.local"
|
66
|
+
end
|
67
|
+
|
67
68
|
end
|
data/lib/capobvious/version.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: capobvious
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.3.
|
4
|
+
version: 0.3.pre1
|
5
5
|
prerelease: 4
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -64,7 +64,10 @@ files:
|
|
64
64
|
- lib/capobvious/recipes/db.rb
|
65
65
|
- lib/capobvious/recipes/delayed_job.rb
|
66
66
|
- lib/capobvious/recipes/import.rb
|
67
|
+
- lib/capobvious/recipes/log.rb
|
67
68
|
- lib/capobvious/recipes/logrotate.rb
|
69
|
+
- lib/capobvious/recipes/main.rb
|
70
|
+
- lib/capobvious/recipes/nginx.rb
|
68
71
|
- lib/capobvious/recipes/rake.rb
|
69
72
|
- lib/capobvious/recipes/sitemap_generator.rb
|
70
73
|
- lib/capobvious/recipes/unicorn.rb
|