capistrano-former03 0.0.4 → 0.0.5

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 7eba37d16b1b4df52e00489a08c7ad68efc13791
4
- data.tar.gz: 52f7671a60e5f716fda3bea283479531128a9fb0
3
+ metadata.gz: 9826b5d4e73dfdac22b474e4bb8bbbd6e875fe6d
4
+ data.tar.gz: 7f32d7bdc321264751b5cc5b34943b6100a0a615
5
5
  SHA512:
6
- metadata.gz: 2bf1dbc9f96973cb0353885c22b9944b784dbb7324ab0cc70e39b9b0c5926f6f5ba5c8dd9dfd716fb1eb9cc365a49e215ac89716be481c53d85d297f2d5ce72d
7
- data.tar.gz: 6a3c9678ee37e3bf600db9fe2d763c4f5ae073a40124b1433f34a78f0116db0c67dabeb15a5b315c615c7b689ac04bbd6837baa92a2672dad112c2103342ffac
6
+ metadata.gz: cf00abf2fdbc8797c71903c1498bd8ac965365d5a82d9e6b072675fbd0080b6aa6957578a31485f345afbd9921698c42bb0c79139d154843d9166c06c0905f6f
7
+ data.tar.gz: 8c254a94b18da059f25237de1f6046e6a9eb6c04279ad946c8efd68032878e74c407043fb096c1a4b6a84dee3a1ece7c739d14f7de69ed217460941d8d1556bf
@@ -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
 
@@ -1,5 +1,5 @@
1
1
  module Capistrano
2
2
  module Former03
3
- VERSION = '0.0.4'
3
+ VERSION = '0.0.5'
4
4
  end
5
5
  end
@@ -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
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-03-17 00:00:00.000000000 Z
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