capistrano-former03 0.0.4 → 0.0.5
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.
- checksums.yaml +4 -4
- data/lib/capistrano/former03.rb +3 -0
- data/lib/capistrano/former03/assets.rb +102 -0
- data/lib/capistrano/former03/backup.rb +56 -0
- data/lib/capistrano/former03/mysql.rb +149 -0
- data/lib/capistrano/former03/rsync.rb +6 -1
- data/lib/capistrano/former03/templates/deploy.rb.erb +34 -0
- data/lib/capistrano/former03/templates/stage.rb.erb +13 -0
- data/lib/capistrano/former03/version.rb +1 -1
- data/lib/capistrano/tasks/former03.rake +55 -0
- metadata +5 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 9826b5d4e73dfdac22b474e4bb8bbbd6e875fe6d
|
4
|
+
data.tar.gz: 7f32d7bdc321264751b5cc5b34943b6100a0a615
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: cf00abf2fdbc8797c71903c1498bd8ac965365d5a82d9e6b072675fbd0080b6aa6957578a31485f345afbd9921698c42bb0c79139d154843d9166c06c0905f6f
|
7
|
+
data.tar.gz: 8c254a94b18da059f25237de1f6046e6a9eb6c04279ad946c8efd68032878e74c407043fb096c1a4b6a84dee3a1ece7c739d14f7de69ed217460941d8d1556bf
|
data/lib/capistrano/former03.rb
CHANGED
@@ -2,6 +2,9 @@ require 'capistrano/former03/version'
|
|
2
2
|
require 'capistrano/former03/deploy_command'
|
3
3
|
require 'capistrano/former03/symlink'
|
4
4
|
require 'capistrano/former03/rsync'
|
5
|
+
require 'capistrano/former03/assets'
|
6
|
+
require 'capistrano/former03/mysql'
|
7
|
+
require 'capistrano/former03/backup'
|
5
8
|
load File.expand_path('../tasks/former03.rake', __FILE__)
|
6
9
|
|
7
10
|
module Capistrano
|
@@ -0,0 +1,102 @@
|
|
1
|
+
require 'date'
|
2
|
+
|
3
|
+
module Capistrano
|
4
|
+
module Former03
|
5
|
+
class Assets
|
6
|
+
def initialize
|
7
|
+
end
|
8
|
+
|
9
|
+
def task
|
10
|
+
@task
|
11
|
+
end
|
12
|
+
|
13
|
+
def asset_paths
|
14
|
+
ret_val = fetch(:linked_dirs, [])
|
15
|
+
ret_val += fetch(:linked_files, []).map{|path| File.dirname path}
|
16
|
+
ret_val.uniq
|
17
|
+
end
|
18
|
+
|
19
|
+
def include_paths
|
20
|
+
asset_paths.map do |path|
|
21
|
+
path.split('/').first
|
22
|
+
end.uniq
|
23
|
+
end
|
24
|
+
|
25
|
+
def sync_includes
|
26
|
+
paths = []
|
27
|
+
|
28
|
+
# Add parent dirs
|
29
|
+
asset_paths.each do |p|
|
30
|
+
dir = p
|
31
|
+
paths += ["'/#{p}/***'"]
|
32
|
+
while true
|
33
|
+
dir = File.dirname(dir)
|
34
|
+
break if dir == '.'
|
35
|
+
paths += ["'/#{dir}/'"]
|
36
|
+
end
|
37
|
+
end
|
38
|
+
paths.reverse.map{|p| ['--include', p]}.flatten
|
39
|
+
end
|
40
|
+
|
41
|
+
def sync(t)
|
42
|
+
@task = t
|
43
|
+
if fetch(:assets_source, nil).nil?
|
44
|
+
fail 'No asset source given'
|
45
|
+
end
|
46
|
+
|
47
|
+
if fetch(:stage) == :production
|
48
|
+
fail 'No asset syncing in stage :production'
|
49
|
+
end
|
50
|
+
|
51
|
+
include_opts = sync_includes
|
52
|
+
|
53
|
+
shared_dir = self.shared_dir
|
54
|
+
task.on release_roles :all do
|
55
|
+
rsync = Capistrano::Former03::Rsync.new(
|
56
|
+
:rsync_path => fetch(:deploy_rsync_path),
|
57
|
+
:src_path => fetch(:assets_source),
|
58
|
+
:dest_path => shared_dir,
|
59
|
+
:rsync_options => [
|
60
|
+
'-v',
|
61
|
+
*include_opts,
|
62
|
+
'--exclude', "'/**'",
|
63
|
+
]
|
64
|
+
)
|
65
|
+
execute(*rsync.command)
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
def shared_dir
|
70
|
+
deploy_path.join('shared')
|
71
|
+
end
|
72
|
+
|
73
|
+
def backup(t)
|
74
|
+
@task = t
|
75
|
+
shared_dir = self.shared_dir
|
76
|
+
include_paths = self.include_paths
|
77
|
+
task.on release_roles :all do
|
78
|
+
output_dir = fetch(:backup_dest_path)
|
79
|
+
|
80
|
+
# test for backup dir
|
81
|
+
execute "test -d \"#{output_dir}\" || mkdir -p \"#{output_dir}\""
|
82
|
+
|
83
|
+
if include_paths.length < 1
|
84
|
+
fail "No assets found to backup"
|
85
|
+
end
|
86
|
+
|
87
|
+
existing_dirs = capture(:ls, '-xtr', shared_dir).split
|
88
|
+
exclude_dirs = existing_dirs - include_paths
|
89
|
+
|
90
|
+
# destination dir
|
91
|
+
output = File.join(output_dir, 'assets.tar.gz')
|
92
|
+
|
93
|
+
# build exclude options
|
94
|
+
exclude_opts = exclude_dirs.map {|d| ['--exclude', d] }.flatten
|
95
|
+
|
96
|
+
# compress asset
|
97
|
+
execute(:tar, '-C', shared_dir, '-czf', output, '.', *exclude_opts)
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|
101
|
+
end
|
102
|
+
end
|
@@ -0,0 +1,56 @@
|
|
1
|
+
require 'date'
|
2
|
+
|
3
|
+
module Capistrano
|
4
|
+
module Former03
|
5
|
+
class Backup
|
6
|
+
def initialize
|
7
|
+
end
|
8
|
+
|
9
|
+
def cleanup(t)
|
10
|
+
# minimum age in days to keep backups
|
11
|
+
backup_min_age = fetch(:backup_min_age, 7)
|
12
|
+
# minimum backup count to keep
|
13
|
+
backup_min_count = fetch(:backup_min_count, 5)
|
14
|
+
|
15
|
+
on release_roles :all do
|
16
|
+
backup_dir_path = fetch(:backup_dir_path)
|
17
|
+
backups = capture(:ls, '-xtr', backup_dir_path).split
|
18
|
+
count = 0
|
19
|
+
|
20
|
+
# Loop through existing backups
|
21
|
+
backups.reverse.each do |backup|
|
22
|
+
count += 1
|
23
|
+
created = DateTime.strptime(backup, '%Y%m%d%H%M%S')
|
24
|
+
age = (DateTime.now - created)
|
25
|
+
|
26
|
+
# If backup is older and count is higher than minimums
|
27
|
+
if age.to_i > backup_min_age and count > backup_min_count
|
28
|
+
execute 'rm', '-rf', File.join(backup_dir_path, backup)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
def prepare(t)
|
35
|
+
t.set(:backup_dir_path, File.join(t.fetch(:deploy_to), t.fetch(:backup_dir, 'backups')))
|
36
|
+
on release_roles :all do
|
37
|
+
# set destination path
|
38
|
+
t.set(
|
39
|
+
:backup_dest_path,
|
40
|
+
File.join(
|
41
|
+
fetch(:backup_dir_path),
|
42
|
+
fetch(:release_timestamp,'not_time')
|
43
|
+
)
|
44
|
+
)
|
45
|
+
# ensure directories
|
46
|
+
[fetch(:backup_dir_path)].each do |dir|
|
47
|
+
if not test("test -d #{dir}")
|
48
|
+
execute :mkdir, dir
|
49
|
+
execute :chmod, '0700', dir
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
@@ -0,0 +1,149 @@
|
|
1
|
+
require 'tempfile'
|
2
|
+
|
3
|
+
module Capistrano
|
4
|
+
module Former03
|
5
|
+
class Namespace
|
6
|
+
def initialize(hash)
|
7
|
+
hash.each do |key, value|
|
8
|
+
singleton_class.send(:define_method, key) { value }
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
def get_binding
|
13
|
+
binding
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
class MySQL
|
18
|
+
def initialize
|
19
|
+
end
|
20
|
+
|
21
|
+
def task
|
22
|
+
if @task.nil?
|
23
|
+
fail "No object handle"
|
24
|
+
end
|
25
|
+
@task
|
26
|
+
end
|
27
|
+
|
28
|
+
def sync(t)
|
29
|
+
@task = t
|
30
|
+
src_stage = :production
|
31
|
+
dst_stage = fetch(:stage)
|
32
|
+
|
33
|
+
if src_stage == dst_stage
|
34
|
+
fail "Source stage (#{src_stage}) is equal to destination stage (#{dst_stage})"
|
35
|
+
end
|
36
|
+
|
37
|
+
src_database = config(src_stage)[:database]
|
38
|
+
dst_database = config(dst_stage)[:database]
|
39
|
+
src_cnf = mysql_cnf_upload(:src, src_stage)
|
40
|
+
dst_cnf = mysql_cnf_upload(:dst, dst_stage)
|
41
|
+
|
42
|
+
@task.on release_roles :all do
|
43
|
+
|
44
|
+
# remove all tables on dest
|
45
|
+
tables = capture "mysql --defaults-file=#{dst_cnf} -e'SHOW TABLES;' #{dst_database}"
|
46
|
+
tables = tables.split
|
47
|
+
if tables.length > 1
|
48
|
+
tables = tables[1..-1].map{|name| "`#{name}`"}.join(',')
|
49
|
+
execute "mysql --defaults-file=#{dst_cnf} -e'DROP TABLES #{tables};' #{dst_database}"
|
50
|
+
end
|
51
|
+
|
52
|
+
# sync production to stage
|
53
|
+
execute "mysqldump --defaults-file=#{src_cnf} #{src_database} | mysql --defaults-file=#{dst_cnf} #{dst_database}"
|
54
|
+
|
55
|
+
# remove credentials
|
56
|
+
execute "rm #{src_cnf}"
|
57
|
+
execute "rm #{dst_cnf}"
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
def config(stage=nil)
|
62
|
+
@config ||= task.fetch(:mysql_connections)
|
63
|
+
stage ||= task.fetch(:stage)
|
64
|
+
@config[stage]
|
65
|
+
end
|
66
|
+
|
67
|
+
|
68
|
+
def deploy_to
|
69
|
+
@task.fetch(:deploy_to)
|
70
|
+
end
|
71
|
+
|
72
|
+
def cnf_path(name)
|
73
|
+
File.join(deploy_to, 'shared', ".my.cnf_#{name}")
|
74
|
+
end
|
75
|
+
|
76
|
+
def mysql_cnf_upload(name, stage=nil)
|
77
|
+
dest = cnf_path(name)
|
78
|
+
src = Tempfile.new('my.cnf')
|
79
|
+
src.write(mysql_cnf(stage))
|
80
|
+
src.flush
|
81
|
+
@task.on release_roles :all do
|
82
|
+
upload!(src.path, dest)
|
83
|
+
execute "chmod 600 #{dest}"
|
84
|
+
end
|
85
|
+
|
86
|
+
# remove tempfile
|
87
|
+
src.delete
|
88
|
+
|
89
|
+
dest
|
90
|
+
end
|
91
|
+
|
92
|
+
def mysql_cnf(stage=nil)
|
93
|
+
c=config(stage)
|
94
|
+
output = "[client]\n"
|
95
|
+
output +="user=#{c[:username]}\n" if c.has_key?(:username)
|
96
|
+
output +="password=#{c[:password]}\n" if c.has_key?(:password)
|
97
|
+
output +="host=#{c[:host]}\n" if c.has_key?(:host)
|
98
|
+
output +="port=#{c[:port]}\n" if c.has_key?(:port)
|
99
|
+
end
|
100
|
+
|
101
|
+
def backup(t)
|
102
|
+
@task = t
|
103
|
+
cnf = mysql_cnf_upload(:backup)
|
104
|
+
database = config[:database]
|
105
|
+
# run backup
|
106
|
+
@task.on release_roles :all do
|
107
|
+
output_dir = fetch(:backup_dest_path)
|
108
|
+
|
109
|
+
# test for backup dir
|
110
|
+
execute "test -d \"#{output_dir}\" || mkdir -p \"#{output_dir}\""
|
111
|
+
|
112
|
+
# backup mysqldb
|
113
|
+
output = File.join(output_dir, 'mysql.sql.gz')
|
114
|
+
execute "mysqldump --defaults-file=#{cnf} #{database} | gzip > #{output}"
|
115
|
+
execute "chmod 600 #{output}"
|
116
|
+
|
117
|
+
# remove credentials
|
118
|
+
execute "rm #{cnf}"
|
119
|
+
end
|
120
|
+
end
|
121
|
+
|
122
|
+
def templates(t)
|
123
|
+
@task = t
|
124
|
+
fetch(:mysql_templates, []).each do |c|
|
125
|
+
|
126
|
+
dest = File.join(fetch(:local_stage_path), c[:destination])
|
127
|
+
|
128
|
+
puts("Evaluting template '#{c[:template]}' to '#{dest}'")
|
129
|
+
|
130
|
+
# Read template
|
131
|
+
erb = ERB.new(
|
132
|
+
File.read(c[:template]),
|
133
|
+
nil,
|
134
|
+
'-',
|
135
|
+
)
|
136
|
+
|
137
|
+
File.open(dest, 'w') do |file|
|
138
|
+
namespace = Namespace.new({
|
139
|
+
config: config(),
|
140
|
+
stage: fetch(:stage),
|
141
|
+
})
|
142
|
+
file.write(erb.result(namespace.get_binding))
|
143
|
+
end
|
144
|
+
File.exist?(c[:destination])
|
145
|
+
end
|
146
|
+
end
|
147
|
+
end
|
148
|
+
end
|
149
|
+
end
|
@@ -107,7 +107,12 @@ module Capistrano
|
|
107
107
|
options += fetch(:rsync_options)
|
108
108
|
|
109
109
|
# Add remote options if needed
|
110
|
-
options += remote_options
|
110
|
+
options += remote_options
|
111
|
+
|
112
|
+
# Add supplied options
|
113
|
+
if not @rsync_options.nil?
|
114
|
+
options += @rsync_options
|
115
|
+
end
|
111
116
|
|
112
117
|
# Add source and destination
|
113
118
|
options += [src_path, dest_path]
|
@@ -22,6 +22,40 @@ set :application, '<MY_APP_NAME>'
|
|
22
22
|
# 'wwwroot/public_writable_dir' => '777',
|
23
23
|
#}
|
24
24
|
|
25
|
+
# Set mysql connnections settings
|
26
|
+
#set :mysql_connections, {
|
27
|
+
# :production => {
|
28
|
+
# :host => 'host1',
|
29
|
+
# :port => 3306,
|
30
|
+
# :database => 'dbname',
|
31
|
+
# :username => 'user1',
|
32
|
+
# :password => 'password',
|
33
|
+
# },
|
34
|
+
# :staging => {
|
35
|
+
# :host => 'host1',
|
36
|
+
# :port => 3306,
|
37
|
+
# :database => 'dbname',
|
38
|
+
# :username => 'user1',
|
39
|
+
# :password => 'password',
|
40
|
+
# },
|
41
|
+
#}
|
42
|
+
|
43
|
+
# Create files from database settings
|
44
|
+
#set :mysql_templates, [
|
45
|
+
# {
|
46
|
+
# :destination => 'wwwroot/wp-database.php',
|
47
|
+
# :template => 'config/wp-database.php.erb',
|
48
|
+
# }
|
49
|
+
#]
|
50
|
+
# Enable mysql templates
|
51
|
+
#before 'former03:local:fix_rights', 'former03:mysql:templates'
|
52
|
+
|
53
|
+
# Create mysqldump before deploy
|
54
|
+
#before 'former03:remote:release', 'former03:mysql:backup'
|
55
|
+
|
56
|
+
# Perform asset backup before deploy
|
57
|
+
#before 'former03:remote:release', 'former03:assets:backup'
|
58
|
+
|
25
59
|
# Execute custom task after local stage (example default task)
|
26
60
|
=begin
|
27
61
|
namespace :custom do
|
@@ -16,6 +16,19 @@ set :ssh_options, {
|
|
16
16
|
}
|
17
17
|
=end
|
18
18
|
|
19
|
+
# Sync database from production
|
20
|
+
# * use in non production stages only
|
21
|
+
# * performs mysqldump backup
|
22
|
+
#before 'former03:remote:release', 'former03:mysql:sync'
|
23
|
+
|
24
|
+
# Sync asstes from production
|
25
|
+
# * use in non production stages only
|
26
|
+
# * no backup is performed
|
27
|
+
=begin
|
28
|
+
set(:assets_source, '/path/to/productions/shared/')
|
29
|
+
before 'former03:remote:release', 'former03:assets:sync'
|
30
|
+
=end
|
31
|
+
|
19
32
|
# Destination directory for deployment
|
20
33
|
set :deploy_to, '<DESTDIR>'
|
21
34
|
|
@@ -19,6 +19,9 @@ namespace :former03 do
|
|
19
19
|
set :relative_symlinks, true
|
20
20
|
set :current_path_real_dir, false
|
21
21
|
|
22
|
+
set :mysql_connections, {}
|
23
|
+
set :mysql_templates, []
|
24
|
+
|
22
25
|
set :ensure_file_mode, nil
|
23
26
|
set :ensure_dir_mode, nil
|
24
27
|
set :ensure_path_mode, {}
|
@@ -169,6 +172,21 @@ namespace :former03 do
|
|
169
172
|
|
170
173
|
namespace :remote do
|
171
174
|
|
175
|
+
desc 'Cleanup remote backup'
|
176
|
+
task :backup_cleanup => :backup_prepare do
|
177
|
+
@backup.cleanup self
|
178
|
+
end
|
179
|
+
|
180
|
+
desc 'Prepare remote backup'
|
181
|
+
task :backup_prepare => :"deploy:new_release_path" do
|
182
|
+
@backup ||= Capistrano::Former03::Backup.new
|
183
|
+
@backup.prepare self
|
184
|
+
end
|
185
|
+
|
186
|
+
desc 'Do a remote backup'
|
187
|
+
task :backup => :backup_cleanup do
|
188
|
+
end
|
189
|
+
|
172
190
|
desc 'Check the deployment hosts'
|
173
191
|
task :check => [
|
174
192
|
:mkdir_stage,
|
@@ -277,4 +295,41 @@ namespace :former03 do
|
|
277
295
|
end
|
278
296
|
end
|
279
297
|
end
|
298
|
+
|
299
|
+
namespace :assets do
|
300
|
+
task :prepare do
|
301
|
+
@assets ||= Capistrano::Former03::Assets.new
|
302
|
+
end
|
303
|
+
|
304
|
+
desc 'Create a backup of assets'
|
305
|
+
task :backup => [:prepare, :'former03:remote:backup'] do
|
306
|
+
@assets.backup(self)
|
307
|
+
end
|
308
|
+
|
309
|
+
desc 'Sync production assets to my stage'
|
310
|
+
task :sync => [:prepare] do
|
311
|
+
@assets.sync(self)
|
312
|
+
end
|
313
|
+
end
|
314
|
+
|
315
|
+
namespace :mysql do
|
316
|
+
task :prepare do
|
317
|
+
@mysql ||= Capistrano::Former03::MySQL.new
|
318
|
+
end
|
319
|
+
|
320
|
+
desc 'Sync production database to my stage'
|
321
|
+
task :sync => [:backup, :prepare] do
|
322
|
+
@mysql.sync(self)
|
323
|
+
end
|
324
|
+
|
325
|
+
desc 'Create a mysqldump of the remote databases'
|
326
|
+
task :backup => [:prepare, :'former03:remote:backup'] do
|
327
|
+
@mysql.backup(self)
|
328
|
+
end
|
329
|
+
|
330
|
+
desc 'Create mysql files from templates'
|
331
|
+
task :templates => :prepare do
|
332
|
+
@mysql.templates(self)
|
333
|
+
end
|
334
|
+
end
|
280
335
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: capistrano-former03
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.5
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Christian Simon
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2015-
|
11
|
+
date: 2015-04-26 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: capistrano
|
@@ -96,8 +96,11 @@ files:
|
|
96
96
|
- bin/f03capinstall
|
97
97
|
- capistrano-former03.gemspec
|
98
98
|
- lib/capistrano/former03.rb
|
99
|
+
- lib/capistrano/former03/assets.rb
|
100
|
+
- lib/capistrano/former03/backup.rb
|
99
101
|
- lib/capistrano/former03/deploy_command.rb
|
100
102
|
- lib/capistrano/former03/install.rb
|
103
|
+
- lib/capistrano/former03/mysql.rb
|
101
104
|
- lib/capistrano/former03/rsync.rb
|
102
105
|
- lib/capistrano/former03/symlink.rb
|
103
106
|
- lib/capistrano/former03/templates/Capfile
|