capistrano-db-tasks 0.2

Sign up to get free protection for your applications and to get access to all the features.
data/Gemfile ADDED
@@ -0,0 +1,3 @@
1
+ source 'http://rubygems.org'
2
+
3
+ gemspec
data/LICENSE ADDED
@@ -0,0 +1,16 @@
1
+ Copyright (c) 2009 Sébastien Gruhier - Xilinus/Maptimize
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining a copy
4
+ of this software and associated documentation files (the "Software"), to deal
5
+ in the Software without restriction, including without limitation the rights
6
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7
+ copies of the Software, and to permit persons to whom the Software is
8
+ furnished to do so, subject to the following conditions:
9
+
10
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
11
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
12
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
13
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
14
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
15
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
16
+ SOFTWARE.
data/README.markdown ADDED
@@ -0,0 +1,76 @@
1
+ CapistranoDbTasks
2
+ =================
3
+
4
+ Add database AND assets tasks to capistrano to a Rails project.
5
+
6
+ Currently
7
+
8
+ * It only supports mysql and postgresql (both side remote and local)
9
+ * Synchronize assets remote to local and local to remote
10
+
11
+ Commands mysql, mysqldump (or pg_dump, psql), bzip2 and unbzip2 must be in your PATH
12
+
13
+ Feel free to fork and to add more database support or new tasks.
14
+
15
+ Install
16
+ =======
17
+
18
+ Add it as a gem:
19
+
20
+ ```ruby
21
+ gem "capistrano-db-tasks", require: false
22
+ ```
23
+
24
+ Add to config/deploy.rb:
25
+
26
+ ```ruby
27
+ require 'capistrano-db-tasks'
28
+
29
+ # if you haven't already specified
30
+ set :rails_env, "production"
31
+
32
+ # if you want to remove the dump file after loading
33
+ set :db_local_clean, true
34
+
35
+ # If you want to import assets, you can change default asset dir (default = system)
36
+ # This directory must be in your shared directory on the server
37
+ set :assets_dir, %w(public/assets public/att)
38
+
39
+ # if you want to work on a specific local environment (default = ENV['RAILS_ENV'] || 'development')
40
+ set :locals_rails_env, "production"
41
+ ```
42
+
43
+ Available tasks
44
+ ===============
45
+
46
+ app:local:sync || app:pull # Synchronize your local assets AND database using remote assets and database
47
+ app:remote:sync || app:push # Synchronize your remote assets AND database using local assets and database
48
+
49
+ assets:local:sync || assets:pull # Synchronize your local assets using remote assets
50
+ assets:remote:sync || assets:push # Synchronize your remote assets using local assets
51
+
52
+ db:local:sync || db:pull # Synchronize your local database using remote database data
53
+ db:remote:sync || db:push # Synchronize your remote database using local database data
54
+
55
+ Example
56
+ =======
57
+
58
+ cap db:pull
59
+ cap production db:pull # if you are using capistrano-ext to have multistages
60
+
61
+
62
+ Contributors
63
+ ============
64
+
65
+ * tilsammans (http://github.com/tilsammansee)
66
+ * bigfive (http://github.com/bigfive)
67
+ * jakemauer (http://github.com/jakemauer)
68
+ * tjoneseng (http://github.com/tjoneseng)
69
+
70
+ TODO
71
+ ====
72
+
73
+ * May be change project's name as it's not only database tasks now :)
74
+ * Add tests
75
+
76
+ Copyright (c) 2009 [Sébastien Gruhier - XILINUS], released under the MIT license
data/Rakefile ADDED
@@ -0,0 +1,25 @@
1
+ require 'rake'
2
+ require 'rake/testtask'
3
+ require 'rake/rdoctask'
4
+ require 'bundler'
5
+ require 'bundler/gem_tasks'
6
+
7
+ desc 'Default: run unit tests.'
8
+ task :default => :test
9
+
10
+ desc 'Test the capistrano_db_tasks plugin.'
11
+ Rake::TestTask.new(:test) do |t|
12
+ t.libs << 'lib'
13
+ t.libs << 'test'
14
+ t.pattern = 'test/**/*_test.rb'
15
+ t.verbose = true
16
+ end
17
+
18
+ desc 'Generate documentation for the capistrano_db_tasks plugin.'
19
+ Rake::RDocTask.new(:rdoc) do |rdoc|
20
+ rdoc.rdoc_dir = 'rdoc'
21
+ rdoc.title = 'CapistranoDbTasks'
22
+ rdoc.options << '--line-numbers' << '--inline-source'
23
+ rdoc.rdoc_files.include('README')
24
+ rdoc.rdoc_files.include('lib/**/*.rb')
25
+ end
@@ -0,0 +1,22 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+ require "capistrano-db-tasks/version"
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = "capistrano-db-tasks"
7
+ s.version = CapistranoDbTasks::VERSION
8
+ s.authors = ["Sebastien Gruhier"]
9
+ s.email = ["sebastien.gruhier@xilinus.com"]
10
+ s.homepage = "https://github.com/sgruhier/capistrano-db-tasks"
11
+ s.summary = "A collection of capistrano tasks for syncing assets and databases"
12
+ s.description = "A collection of capistrano tasks for syncing assets and databases"
13
+
14
+ s.rubyforge_project = "capistrano-db-tasks"
15
+
16
+ s.files = `git ls-files`.split("\n")
17
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
18
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
19
+ s.require_paths = ["lib"]
20
+
21
+ s.add_development_dependency "capistrano", "> 2.0.0"
22
+ end
@@ -0,0 +1,23 @@
1
+ module Asset
2
+ extend self
3
+
4
+ def remote_to_local(cap)
5
+ servers = cap.find_servers :roles => :app
6
+ port = cap.port rescue 22
7
+ [cap.assets_dir].flatten.each do |dir|
8
+ system("rsync -a --del -L -K -vv --progress --rsh='ssh -p #{port}' #{cap.user}@#{servers.first}:#{cap.current_path}/#{dir} #{cap.local_assets_dir}")
9
+ end
10
+ end
11
+
12
+ def local_to_remote(cap)
13
+ servers = cap.find_servers :roles => :app
14
+ port = cap.port rescue 22
15
+ [cap.assets_dir].flatten.each do |dir|
16
+ system("rsync -a --del -L -K -vv --progress --rsh='ssh -p #{port}' ./#{dir} #{cap.user}@#{servers.first}:#{cap.current_path}/#{cap.local_assets_dir}")
17
+ end
18
+ end
19
+
20
+ def to_string(cap)
21
+ [cap.assets_dir].flatten.join(" ")
22
+ end
23
+ end
@@ -0,0 +1,141 @@
1
+ module Database
2
+ class Base
3
+ attr_accessor :config, :output_file
4
+ def initialize(cap_instance)
5
+ @cap = cap_instance
6
+ end
7
+
8
+ def mysql?
9
+ @config['adapter'] =~ /^mysql/
10
+ end
11
+
12
+ def postgresql?
13
+ %w(postgresql pg).include? @config['adapter']
14
+ end
15
+
16
+ def credentials
17
+ if mysql?
18
+ " -u #{@config['username']} " + (@config['password'] ? " -p\"#{@config['password']}\" " : '') + (@config['host'] ? " -h #{@config['host']}" : '') + (@config['socket'] ? " -S#{@config['socket']}" : '')
19
+ elsif postgresql?
20
+ " -U #{@config['username']} " + (@config['host'] ? " -h #{@config['host']}" : '')
21
+ end
22
+ end
23
+
24
+ def database
25
+ @config['database']
26
+ end
27
+
28
+ def current_time
29
+ Time.now.strftime("%Y-%m-%d-%H%M%S")
30
+ end
31
+
32
+ def output_file
33
+ @output_file ||= "db/#{database}_#{current_time}.sql.bz2"
34
+ end
35
+
36
+
37
+ private
38
+
39
+ def dump_cmd
40
+ if mysql?
41
+ "mysqldump #{credentials} #{database} --lock-tables=false"
42
+ elsif postgresql?
43
+ "pg_dump #{credentials} -c -O #{database}"
44
+ end
45
+ end
46
+
47
+ def import_cmd(file)
48
+ if mysql?
49
+ "mysql #{credentials} -D #{database} < #{file}"
50
+ elsif postgresql?
51
+ "psql #{credentials} #{database} < #{file}"
52
+ end
53
+ end
54
+
55
+ end
56
+
57
+ class Remote < Base
58
+ def initialize(cap_instance)
59
+ super(cap_instance)
60
+ @config = ""
61
+ @cap.run("cat #{@cap.current_path}/config/database.yml") do |c, s, d|
62
+ @config += d
63
+ end
64
+ @config = YAML.load(@config)[@cap.rails_env]
65
+ end
66
+
67
+ def dump
68
+ @cap.run "cd #{@cap.current_path} && #{dump_cmd} | bzip2 - - > #{output_file}"
69
+ self
70
+ end
71
+
72
+ def download(local_file = "#{output_file}")
73
+ remote_file = "#{@cap.current_path}/#{output_file}"
74
+ @cap.get remote_file, local_file
75
+ end
76
+
77
+ # cleanup = true removes the mysqldump file after loading, false leaves it in db/
78
+ def load(file, cleanup)
79
+ unzip_file = File.join(File.dirname(file), File.basename(file, '.bz2'))
80
+ # @cap.run "cd #{@cap.current_path} && bunzip2 -f #{file} && RAILS_ENV=#{@cap.rails_env} bundle exec rake db:drop db:create && #{import_cmd(unzip_file)}"
81
+ @cap.run "cd #{@cap.current_path} && bunzip2 -f #{file} && RAILS_ENV=#{@cap.rails_env} && #{import_cmd(unzip_file)}"
82
+ @cap.run("cd #{@cap.current_path} && rm #{unzip_file}") if cleanup
83
+ end
84
+ end
85
+
86
+ class Local < Base
87
+ def initialize(cap_instance)
88
+ super(cap_instance)
89
+ @config = YAML.load_file(File.join('config', 'database.yml'))[@cap.local_rails_env]
90
+ puts "local #{@config}"
91
+ end
92
+
93
+ # cleanup = true removes the mysqldump file after loading, false leaves it in db/
94
+ def load(file, cleanup)
95
+ unzip_file = File.join(File.dirname(file), File.basename(file, '.bz2'))
96
+ # system("bunzip2 -f #{file} && bundle exec rake db:drop db:create && #{import_cmd(unzip_file)} && bundle exec rake db:migrate")
97
+ system("bunzip2 -f #{file} && #{import_cmd(unzip_file)}")
98
+ File.unlink(unzip_file) if cleanup
99
+ end
100
+
101
+ def dump
102
+ system "#{dump_cmd} | bzip2 - - > #{output_file}"
103
+ self
104
+ end
105
+
106
+ def upload
107
+ remote_file = "#{@cap.current_path}/#{output_file}"
108
+ @cap.upload output_file, remote_file
109
+ end
110
+ end
111
+
112
+
113
+ class << self
114
+ def check(local_db, remote_db)
115
+ unless (local_db.mysql? && remote_db.mysql?) || (local_db.postgresql? && remote_db.postgresql?)
116
+ raise 'Only mysql or postgresql on remote and local server is supported'
117
+ end
118
+ end
119
+
120
+ def remote_to_local(instance)
121
+ local_db = Database::Local.new(instance)
122
+ remote_db = Database::Remote.new(instance)
123
+
124
+ check(local_db, remote_db)
125
+
126
+ remote_db.dump.download
127
+ local_db.load(remote_db.output_file, instance.fetch(:db_local_clean))
128
+ end
129
+
130
+ def local_to_remote(instance)
131
+ local_db = Database::Local.new(instance)
132
+ remote_db = Database::Remote.new(instance)
133
+
134
+ check(local_db, remote_db)
135
+
136
+ local_db.dump.upload
137
+ remote_db.load(local_db.output_file, instance.fetch(:db_local_clean))
138
+ end
139
+ end
140
+
141
+ end
@@ -0,0 +1,115 @@
1
+ if Capistrano::Configuration.instance(false)
2
+
3
+ Capistrano::Configuration.instance(true).load do |instance|
4
+
5
+ require File.expand_path("#{File.dirname(__FILE__)}/util")
6
+ require File.expand_path("#{File.dirname(__FILE__)}/database")
7
+ require File.expand_path("#{File.dirname(__FILE__)}/asset")
8
+
9
+ instance.set :local_rails_env, ENV['RAILS_ENV'] || 'development' unless exists?(:local_rails_env)
10
+ instance.set :rails_env, 'production' unless exists?(:rails_env)
11
+ instance.set :stage, 'production' unless exists?(:stage)
12
+ instance.set :db_local_clean, false unless exists?(:db_local_clean)
13
+ instance.set :assets_dir, 'system' unless exists?(:assets_dir)
14
+ instance.set :local_assets_dir, 'public' unless exists?(:local_assets_dir)
15
+
16
+ namespace :db do
17
+ namespace :remote do
18
+ desc 'Synchronize your remote database using local database data'
19
+ task :sync, :roles => :db do
20
+ if Util.prompt 'Are you sure you want to REPLACE THE REMOTE DATABASE with local database'
21
+ Database.local_to_remote(instance)
22
+ end
23
+ end
24
+ end
25
+
26
+ namespace :local do
27
+ desc 'Synchronize your local database using remote database data'
28
+ task :sync, :roles => :db do
29
+ puts "Local database: #{Database::Local.new(instance).database}"
30
+ if Util.prompt 'Are you sure you want to erase your local database with server database'
31
+ Database.remote_to_local(instance)
32
+ end
33
+ end
34
+ end
35
+
36
+ desc 'Synchronize your local database using remote database data'
37
+ task :pull do
38
+ db.local.sync
39
+ end
40
+
41
+ desc 'Synchronize your remote database using local database data'
42
+ task :push do
43
+ db.remote.sync
44
+ end
45
+ end
46
+
47
+ namespace :assets do
48
+ namespace :remote do
49
+ desc 'Synchronize your remote assets using local assets'
50
+ task :sync, :roles => :app do
51
+ puts "Assets directories: #{assets_dir}"
52
+ if Util.prompt "Are you sure you want to erase your server assets with local assets"
53
+ Asset.local_to_remote(instance)
54
+ end
55
+ end
56
+ end
57
+
58
+ namespace :local do
59
+ desc 'Synchronize your local assets using remote assets'
60
+ task :sync, :roles => :app do
61
+ puts "Assets directories: #{local_assets_dir}"
62
+ if Util.prompt "Are you sure you want to erase your local assets with server assets"
63
+ Asset.remote_to_local(instance)
64
+ end
65
+ end
66
+ end
67
+
68
+ desc 'Synchronize your local assets using remote assets'
69
+ task :pull do
70
+ assets.local.sync
71
+ end
72
+
73
+ desc 'Synchronize your remote assets using local assets'
74
+ task :push do
75
+ assets.remote.sync
76
+ end
77
+ end
78
+
79
+ namespace :app do
80
+ namespace :remote do
81
+ desc 'Synchronize your remote assets AND database using local assets and database'
82
+ task :sync do
83
+ if Util.prompt "Are you sure you want to REPLACE THE REMOTE DATABASE AND your remote assets with local database and assets(#{assets_dir})"
84
+ Database.local_to_remote(instance)
85
+ Asset.local_to_remote(instance)
86
+ end
87
+ end
88
+ end
89
+
90
+ namespace :local do
91
+ desc 'Synchronize your local assets AND database using remote assets and database'
92
+ task :sync do
93
+ puts "Local database : #{Database::Local.new(instance).database}"
94
+ puts "Assets directories : #{local_assets_dir}"
95
+ if Util.prompt "Are you sure you want to erase your local database AND your local assets with server database and assets(#{assets_dir})"
96
+ Database.remote_to_local(instance)
97
+ Asset.remote_to_local(instance)
98
+ end
99
+ end
100
+ end
101
+
102
+ desc 'Synchronize your local assets AND database using remote assets and database'
103
+ task :pull do
104
+ app.local.sync
105
+ end
106
+
107
+ desc 'Synchronize your remote assets AND database using local assets and database'
108
+ task :push do
109
+ app.remote.sync
110
+ end
111
+
112
+ end
113
+ end
114
+
115
+ end
@@ -0,0 +1,10 @@
1
+ module Util
2
+ def self.prompt(msg, prompt = "(y)es, (n)o ")
3
+ answer = Capistrano::CLI.ui.ask("#{msg} #{prompt} ? ") do |q|
4
+ q.overwrite = false
5
+ q.validate = /^y$|^yes$|^n$|^no$/i
6
+ q.responses[:not_valid] = prompt
7
+ end
8
+ (answer =~ /^y$|^yes$/i) == 0
9
+ end
10
+ end
@@ -0,0 +1,3 @@
1
+ module CapistranoDbTasks
2
+ VERSION = "0.2"
3
+ end
@@ -0,0 +1,2 @@
1
+ require "capistrano"
2
+ require File.expand_path("#{File.dirname(__FILE__)}/capistrano-db-tasks/dbtasks")
@@ -0,0 +1,8 @@
1
+ require 'test_helper'
2
+
3
+ class CapistranoDbTasksTest < ActiveSupport::TestCase
4
+ # Replace this with your real tests.
5
+ test "the truth" do
6
+ assert true
7
+ end
8
+ end
@@ -0,0 +1,3 @@
1
+ require 'rubygems'
2
+ require 'active_support'
3
+ require 'active_support/test_case'
metadata ADDED
@@ -0,0 +1,76 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: capistrano-db-tasks
3
+ version: !ruby/object:Gem::Version
4
+ version: '0.2'
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Sebastien Gruhier
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2013-01-09 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: capistrano
16
+ requirement: !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ! '>'
20
+ - !ruby/object:Gem::Version
21
+ version: 2.0.0
22
+ type: :development
23
+ prerelease: false
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ! '>'
28
+ - !ruby/object:Gem::Version
29
+ version: 2.0.0
30
+ description: A collection of capistrano tasks for syncing assets and databases
31
+ email:
32
+ - sebastien.gruhier@xilinus.com
33
+ executables: []
34
+ extensions: []
35
+ extra_rdoc_files: []
36
+ files:
37
+ - Gemfile
38
+ - LICENSE
39
+ - README.markdown
40
+ - Rakefile
41
+ - capistrano-db-tasks.gemspec
42
+ - lib/capistrano-db-tasks.rb
43
+ - lib/capistrano-db-tasks/asset.rb
44
+ - lib/capistrano-db-tasks/database.rb
45
+ - lib/capistrano-db-tasks/dbtasks.rb
46
+ - lib/capistrano-db-tasks/util.rb
47
+ - lib/capistrano-db-tasks/version.rb
48
+ - test/capistrano_db_tasks_test.rb
49
+ - test/test_helper.rb
50
+ homepage: https://github.com/sgruhier/capistrano-db-tasks
51
+ licenses: []
52
+ post_install_message:
53
+ rdoc_options: []
54
+ require_paths:
55
+ - lib
56
+ required_ruby_version: !ruby/object:Gem::Requirement
57
+ none: false
58
+ requirements:
59
+ - - ! '>='
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ required_rubygems_version: !ruby/object:Gem::Requirement
63
+ none: false
64
+ requirements:
65
+ - - ! '>='
66
+ - !ruby/object:Gem::Version
67
+ version: '0'
68
+ requirements: []
69
+ rubyforge_project: capistrano-db-tasks
70
+ rubygems_version: 1.8.23
71
+ signing_key:
72
+ specification_version: 3
73
+ summary: A collection of capistrano tasks for syncing assets and databases
74
+ test_files:
75
+ - test/capistrano_db_tasks_test.rb
76
+ - test/test_helper.rb