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 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