Skip to content

Allow to specify privileged user for database drop/create (PostgreSQL only) #79

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
108 changes: 108 additions & 0 deletions README.markdown
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
CapistranoDbTasks
=================

Add database AND assets tasks to capistrano to a Rails project.
It only works with capistrano 3. Older versions until 0.3 works with capistrano 2.

Currently

* It only supports mysql and postgresql (both side remote and local)
* Synchronize assets remote to local and local to remote

Commands mysql, mysqldump (or pg\_dump, psql), bzip2 and unbzip2 (or gzip) must be in your PATH

Feel free to fork and to add more database support or new tasks.

Install
=======

Add it as a gem:

```ruby
gem "capistrano-db-tasks", require: false
```

Add to config/deploy.rb:

```ruby
require 'capistrano-db-tasks'

# if you haven't already specified
set :rails_env, "production"

# if you want to remove the local dump file after loading
set :db_local_clean, true

# if you want to remove the dump file from the server after downloading
set :db_remote_clean, true

# if you want to exclude table from dump
set :db_ignore_tables, []

# if you want to exclude table data (but not table schema) from dump
set :db_ignore_data_tables, []

# If you want to import assets, you can change default asset dir (default = system)
# This directory must be in your shared directory on the server
set :assets_dir, %w(public/assets public/att)
set :local_assets_dir, %w(public/assets public/att)

# if you want to work on a specific local environment (default = ENV['RAILS_ENV'] || 'development')
set :locals_rails_env, "production"

# if you are highly paranoid and want to prevent any push operation to the server
set :disallow_pushing, true

# if you prefer bzip2/unbzip2 instead of gzip
set :compressor, :bzip2

# If you want to use privileged user to drop/create database on remote or local host (PostgreSQL only)
set :db_remote_superuser, 'postgres'
set :db_remote_superuser_password, 'secret'
set :db_local_superuser, 'postgres'
set :db_local_superuser_password, 'secret'

```

Add to .gitignore
```yml
/db/*.sql
```


[How to install bzip2 on Windows](http://stackoverflow.com/a/25625988/3324219)

Available tasks
===============

app:local:sync || app:pull # Synchronize your local assets AND database using remote assets and database
app:remote:sync || app:push # Synchronize your remote assets AND database using local assets and database

assets:local:sync || assets:pull # Synchronize your local assets using remote assets
assets:remote:sync || assets:push # Synchronize your remote assets using local assets

db:local:sync || db:pull # Synchronize your local database using remote database data
db:remote:sync || db:push # Synchronize your remote database using local database data

Example
=======

cap db:pull
cap production db:pull # if you are using capistrano-ext to have multistages


Contributors
============

* tilsammans (http://github.com/tilsammansee)
* bigfive (http://github.com/bigfive)
* jakemauer (http://github.com/jakemauer)
* tjoneseng (http://github.com/tjoneseng)

TODO
====

* May be change project's name as it's not only database tasks now :)
* Add tests

Copyright (c) 2009 [Sébastien Gruhier - XILINUS], released under the MIT license
33 changes: 18 additions & 15 deletions lib/capistrano-db-tasks/database.rb
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,14 @@ def postgresql?
%w(postgresql pg postgis).include? @config['adapter']
end

def credentials
def credentials(options = {superuser: false})
credential_params = ""
username = @config['username'] || @config['user']
username = (options[:superuser] && @cap.fetch("db_#{options[:location]}_superuser".to_sym)) || @config['username'] || @config['user']
password = (options[:superuser] && @cap.fetch("db_#{options[:location]}_superuser_password".to_sym)) || @config['password']

if mysql?
credential_params << " -u #{username} " if username
credential_params << " -p'#{@config['password']}' " if @config['password']
credential_params << " -p'#{password}' " if password
credential_params << " -h #{@config['host']} " if @config['host']
credential_params << " -S #{@config['socket']} " if @config['socket']
credential_params << " -P #{@config['port']} " if @config['port']
Expand Down Expand Up @@ -58,8 +59,9 @@ def compressor

private

def pgpass
@config['password'] ? "PGPASSWORD='#{@config['password']}'" : ""
def pgpass(options = {superuser: false})
password = (options[:superuser] && @cap.fetch("db_#{options[:location]}_superuser_password".to_sym)) || @config['password']
password ? "PGPASSWORD='#{password}'" : ""
end

def dump_cmd
Expand All @@ -70,12 +72,15 @@ def dump_cmd
end
end

def import_cmd(file)
def import_cmd(file, location = :remote)
if mysql?
"mysql #{credentials} -D #{database} < #{file}"
elsif postgresql?
owner = @config['username'] || @config['user']
pg_password = pgpass(superuser: true, location: location)
pg_credentials = credentials(superuser: true, location: location)
terminate_connection_sql = "SELECT pg_terminate_backend(pg_stat_activity.pid) FROM pg_stat_activity WHERE pg_stat_activity.datname = '#{database}' AND pid <> pg_backend_pid();"
"#{pgpass} psql -c \"#{terminate_connection_sql};\" #{credentials} #{database}; #{pgpass} dropdb #{credentials} #{database}; #{pgpass} createdb #{credentials} #{database}; #{pgpass} psql #{credentials} -d #{database} < #{file}"
"#{pg_password} psql -c \"#{terminate_connection_sql};\" #{pg_credentials} #{database}; #{pg_password} dropdb #{pg_credentials} #{database}; #{pg_password} createdb #{pg_credentials} --owner=#{owner} #{database}; #{pgpass} psql #{credentials} -d #{database} < #{file}"
end
end

Expand Down Expand Up @@ -108,10 +113,8 @@ def initialize(cap_instance)
puts "Loading remote database config"
@cap.within @cap.current_path do
@cap.with rails_env: @cap.fetch(:rails_env) do
dirty_config_content = @cap.capture(:rails, "runner \"puts '#{DBCONFIG_BEGIN_FLAG}' + ActiveRecord::Base.connection.instance_variable_get(:@config).to_yaml + '#{DBCONFIG_END_FLAG}'\"", '2>/dev/null')
# Remove all warnings, errors and artefacts produced by bunlder, rails and other useful tools
config_content = dirty_config_content.match(/#{DBCONFIG_BEGIN_FLAG}(.*?)#{DBCONFIG_END_FLAG}/m)[1]
@config = YAML.load(config_content).each_with_object({}) { |(k, v), h| h[k.to_s] = v }
config_content = @cap.capture(:cat, "config/database.yml")
@config = YAML.load(config_content)[@cap.fetch(:rails_env).to_s].each_with_object({}) { |(k, v), h| h[k.to_s] = v }
end
end
end
Expand Down Expand Up @@ -157,12 +160,12 @@ def initialize(cap_instance)
super(cap_instance)
puts "Loading local database config"
dir_with_escaped_spaces = Dir.pwd.gsub ' ', '\ '
command = "#{dir_with_escaped_spaces}/bin/rails runner \"puts '#{DBCONFIG_BEGIN_FLAG}' + ActiveRecord::Base.connection.instance_variable_get(:@config).to_yaml + '#{DBCONFIG_END_FLAG}'\""
stdout, status = Open3.capture2(command)
command = "cat config/database.yml"
config_content, status = Open3.capture2(command)
raise "Error running command (status=#{status}): #{command}" if status != 0

config_content = stdout.match(/#{DBCONFIG_BEGIN_FLAG}(.*?)#{DBCONFIG_END_FLAG}/m)[1]
@config = YAML.load(config_content).each_with_object({}) { |(k, v), h| h[k.to_s] = v }
local_env = ENV['RAILS_ENV'] || 'development'
@config = YAML.load(config_content)[local_env].each_with_object({}) { |(k, v), h| h[k.to_s] = v }
end

# cleanup = true removes the mysqldump file after loading, false leaves it in db/
Expand Down