cap-taffy 0.0.2
Sign up to get free protection for your applications and to get access to all the features.
- data/History.txt +9 -0
- data/README.md +83 -0
- data/Rakefile +34 -0
- data/cap-taffy.gemspec +45 -0
- data/lib/cap-taffy/db.rb +239 -0
- data/lib/cap-taffy/parse.rb +53 -0
- data/lib/cap-taffy/ssh.rb +18 -0
- data/lib/cap-taffy.rb +45 -0
- data/spec/cap-taffy/db_spec.rb +287 -0
- data/spec/cap-taffy/parse_spec.rb +57 -0
- data/spec/cap-taffy/ssh_spec.rb +37 -0
- data/spec/cap-taffy_spec.rb +4 -0
- data/spec/spec.opts +4 -0
- data/spec/spec_helper.rb +179 -0
- data/tasks/ann.rake +80 -0
- data/tasks/bones.rake +20 -0
- data/tasks/gem.rake +201 -0
- data/tasks/git.rake +40 -0
- data/tasks/notes.rake +27 -0
- data/tasks/post_load.rake +34 -0
- data/tasks/rdoc.rake +51 -0
- data/tasks/rubyforge.rake +55 -0
- data/tasks/setup.rb +292 -0
- data/tasks/spec.rake +54 -0
- data/tasks/svn.rake +47 -0
- data/tasks/test.rake +40 -0
- data/tasks/zentest.rake +36 -0
- metadata +131 -0
data/History.txt
ADDED
data/README.md
ADDED
@@ -0,0 +1,83 @@
|
|
1
|
+
Capistrano Taffy (Database, SSH recipes)
|
2
|
+
================================================
|
3
|
+
|
4
|
+
**Capistrano recipes for deploying databases and other common tasks (managing database.yml, importing/exporting/transfering databases, SSH authorization etc.)**
|
5
|
+
|
6
|
+
Features
|
7
|
+
------------------------------------------------
|
8
|
+
|
9
|
+
* Adds database transfer recipes (via [`Taps`]("http://github.com/ricardochimal/taps"))
|
10
|
+
* Authorize SSH access
|
11
|
+
* Manage `database.yml` (Soon.)
|
12
|
+
|
13
|
+
[`Taps`]("http://github.com/ricardochimal/taps") is great, but having to SSH into my deployment to run the `Taps` server, as well as
|
14
|
+
figure out the proper local/remote database urls, is a pain. I knew the [`Heroku`]("http://github.com/heroku/heroku") gem
|
15
|
+
had it figured out; I present the Capistrano friendly version.
|
16
|
+
|
17
|
+
If you are new to `Taps`, check out this [introduction to `Taps`]("http://adam.blog.heroku.com/past/2009/2/11/taps_for_easy_database_transfers/") by [Adam Wiggins]("http://github.com/adamwiggins").
|
18
|
+
|
19
|
+
Installation
|
20
|
+
------------------------------------------------
|
21
|
+
|
22
|
+
gem install cap-taffy
|
23
|
+
|
24
|
+
Database Transfer
|
25
|
+
------------------------------------------------
|
26
|
+
|
27
|
+
> _Dependency:_ The [`Taps`]("http://github.com/ricardochimal/taps") gem is required on any server(s) you'll be transferring databases to (`:app` role) including your development machine (where you'll be running `cap` tasks from). Run:
|
28
|
+
|
29
|
+
> gem install taps
|
30
|
+
|
31
|
+
> _Dependency:_ The [`Heroku`]("http://github.com/heroku/heroku") gem is required on your development machine.
|
32
|
+
|
33
|
+
> gem install heroku
|
34
|
+
|
35
|
+
### Usage
|
36
|
+
|
37
|
+
To start, add the following to your `Capfile`
|
38
|
+
|
39
|
+
require 'cap-taffy/db'
|
40
|
+
|
41
|
+
`Taffy` will start a `Taps` server on port 5000 by default, so make sure port 5000 (or w/e port you end up using) is open on your `:app` server(s)
|
42
|
+
|
43
|
+
Then you can use:
|
44
|
+
|
45
|
+
cap db:push # Or to specify a different port: cap db:push -s taps_port=4321
|
46
|
+
cap db:pull # Or to specify a different port: cap db:pull -s taps_port=4321
|
47
|
+
|
48
|
+
|
49
|
+
#### SSH Local Forwarding
|
50
|
+
|
51
|
+
> Some of you may not be able/want to open up ports on your servers. Instead, you can run:
|
52
|
+
|
53
|
+
> ssh -N -L[port]:127.0.0.1:[port] [user]@[remote-server]
|
54
|
+
> And then run:
|
55
|
+
|
56
|
+
> cap db:push -s taps_port=[port] -s local=true
|
57
|
+
> Substituing the appropriate values for [port], [user], and [remote-server].
|
58
|
+
> #### Sample Usage
|
59
|
+
> > ssh -N -L4321:127.0.0.1:4321 henry@load-test
|
60
|
+
> > cap db:push -s taps_port=4321 -s local=true
|
61
|
+
|
62
|
+
SSH Access
|
63
|
+
------------------------------------------------
|
64
|
+
|
65
|
+
#### Usage
|
66
|
+
|
67
|
+
Add the following to your `Capfile`
|
68
|
+
|
69
|
+
require 'cap-taffy/ssh'
|
70
|
+
|
71
|
+
Using a public key generated from `ssh-keygen` (e.g. `ssh-keygen -t rsa`), to authorize access:
|
72
|
+
|
73
|
+
cap ssh:authorize # authorizes local public key for SSH access to remote server(s)
|
74
|
+
|
75
|
+
|
76
|
+
Managing `database.yml`
|
77
|
+
------------------------------------------------
|
78
|
+
|
79
|
+
> Much needed and coming soon.
|
80
|
+
|
81
|
+
Credits
|
82
|
+
------------------------------------------------
|
83
|
+
Thanks to developers of the [`Taps`]("http://adam.blog.heroku.com/past/2009/2/11/taps_for_easy_database_transfers/") gem and the [`Heroku`]("http://github.com/heroku/heroku") gem. And of course, Capistrano, awesome!
|
data/Rakefile
ADDED
@@ -0,0 +1,34 @@
|
|
1
|
+
# Look in the tasks/setup.rb file for the various options that can be
|
2
|
+
# configured in this Rakefile. The .rake files in the tasks directory
|
3
|
+
# are where the options are used.
|
4
|
+
|
5
|
+
begin
|
6
|
+
require 'bones'
|
7
|
+
Bones.setup
|
8
|
+
rescue LoadError
|
9
|
+
begin
|
10
|
+
load 'tasks/setup.rb'
|
11
|
+
rescue LoadError
|
12
|
+
raise RuntimeError, '### please install the "bones" gem ###'
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
ensure_in_path 'lib'
|
17
|
+
require 'cap-taffy'
|
18
|
+
|
19
|
+
task :default => 'spec:run'
|
20
|
+
|
21
|
+
PROJ.name = 'cap-taffy'
|
22
|
+
PROJ.authors = 'Henry Hsu'
|
23
|
+
PROJ.email = 'henry@qlane.com'
|
24
|
+
PROJ.url = 'http://by.qlane.com'
|
25
|
+
PROJ.version = CapTaffy::VERSION
|
26
|
+
PROJ.rubyforge.name = 'cap-taffy'
|
27
|
+
PROJ.readme_file = "README.md"
|
28
|
+
PROJ.gem.dependencies = ['heroku', 'taps', 'capistrano']
|
29
|
+
PROJ.gem.development_dependencies << ["mocha"]
|
30
|
+
PROJ.description = "Capistrano recipes for deploying databases and other common tasks."
|
31
|
+
PROJ.summary = "Capistrano recipes for deploying databases (managing database.yml, importing/exporting/transfering databases, etc.)"
|
32
|
+
PROJ.ignore_file = '.gitignore'
|
33
|
+
PROJ.spec.opts << '--color'
|
34
|
+
PROJ.exclude << "bin"
|
data/cap-taffy.gemspec
ADDED
@@ -0,0 +1,45 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
|
3
|
+
Gem::Specification.new do |s|
|
4
|
+
s.name = %q{cap-taffy}
|
5
|
+
s.version = "0.0.2"
|
6
|
+
|
7
|
+
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
8
|
+
s.authors = ["Henry Hsu"]
|
9
|
+
s.date = %q{2009-09-17}
|
10
|
+
s.description = %q{Capistrano recipes for deploying databases and other common tasks.}
|
11
|
+
s.email = %q{henry@qlane.com}
|
12
|
+
s.extra_rdoc_files = ["History.txt"]
|
13
|
+
s.files = ["History.txt", "README.md", "Rakefile", "cap-taffy.gemspec", "lib/cap-taffy.rb", "lib/cap-taffy/db.rb", "lib/cap-taffy/parse.rb", "lib/cap-taffy/ssh.rb", "spec/cap-taffy/db_spec.rb", "spec/cap-taffy/parse_spec.rb", "spec/cap-taffy/ssh_spec.rb", "spec/cap-taffy_spec.rb", "spec/spec.opts", "spec/spec_helper.rb"]
|
14
|
+
s.homepage = %q{http://by.qlane.com}
|
15
|
+
s.rdoc_options = ["--main", "README.md"]
|
16
|
+
s.require_paths = ["lib"]
|
17
|
+
s.rubyforge_project = %q{cap-taffy}
|
18
|
+
s.rubygems_version = %q{1.3.5}
|
19
|
+
s.summary = %q{Capistrano recipes for deploying databases (managing database.yml, importing/exporting/transfering databases, etc.)}
|
20
|
+
|
21
|
+
if s.respond_to? :specification_version then
|
22
|
+
current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
|
23
|
+
s.specification_version = 3
|
24
|
+
|
25
|
+
if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
|
26
|
+
s.add_runtime_dependency(%q<heroku>, [">= 0"])
|
27
|
+
s.add_runtime_dependency(%q<taps>, [">= 0"])
|
28
|
+
s.add_runtime_dependency(%q<capistrano>, [">= 0"])
|
29
|
+
s.add_development_dependency(%q<bones>, [">= 2.5.1"])
|
30
|
+
s.add_development_dependency(%q<mocha>, [">= 0"])
|
31
|
+
else
|
32
|
+
s.add_dependency(%q<heroku>, [">= 0"])
|
33
|
+
s.add_dependency(%q<taps>, [">= 0"])
|
34
|
+
s.add_dependency(%q<capistrano>, [">= 0"])
|
35
|
+
s.add_dependency(%q<bones>, [">= 2.5.1"])
|
36
|
+
s.add_dependency(%q<mocha>, [">= 0"])
|
37
|
+
end
|
38
|
+
else
|
39
|
+
s.add_dependency(%q<heroku>, [">= 0"])
|
40
|
+
s.add_dependency(%q<taps>, [">= 0"])
|
41
|
+
s.add_dependency(%q<capistrano>, [">= 0"])
|
42
|
+
s.add_dependency(%q<bones>, [">= 2.5.1"])
|
43
|
+
s.add_dependency(%q<mocha>, [">= 0"])
|
44
|
+
end
|
45
|
+
end
|
data/lib/cap-taffy/db.rb
ADDED
@@ -0,0 +1,239 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
begin
|
3
|
+
gem 'taps', '>= 0.2.8', '< 0.3.0'
|
4
|
+
require 'taps/client_session'
|
5
|
+
rescue LoadError
|
6
|
+
error "Install the Taps gem to use db commands. On most systems this will be:\nsudo gem install taps"
|
7
|
+
end
|
8
|
+
|
9
|
+
require File.join(File.dirname(__FILE__), %w[.. cap-taffy]) unless defined?(CapTaffy)
|
10
|
+
require File.join(File.dirname(__FILE__), 'parse')
|
11
|
+
require 'digest/sha1'
|
12
|
+
|
13
|
+
module CapTaffy::Db
|
14
|
+
extend self
|
15
|
+
|
16
|
+
# Detects the local database url for +env+.
|
17
|
+
#
|
18
|
+
# Looks for <tt>config/database.yml</tt>.
|
19
|
+
def local_database_url(env)
|
20
|
+
return "" unless File.exists?(Dir.pwd + '/config/database.yml')
|
21
|
+
db_config = YAML.load(File.read(Dir.pwd + '/config/database.yml'))
|
22
|
+
|
23
|
+
CapTaffy::Parse.database_url(db_config, env)
|
24
|
+
end
|
25
|
+
|
26
|
+
# Detects the remote database url for +env+ and the current Capistrano +instance+.
|
27
|
+
#
|
28
|
+
# Looks for <tt>config/database.yml</tt> in the +current_path+.
|
29
|
+
def remote_database_url(instance, env)
|
30
|
+
db_yml = instance.capture "cat #{instance.current_path}/config/database.yml"
|
31
|
+
db_config = YAML::load(db_yml)
|
32
|
+
|
33
|
+
CapTaffy::Parse.database_url(db_config, env)
|
34
|
+
end
|
35
|
+
|
36
|
+
# The default server port the Taps server is started on.
|
37
|
+
def default_server_port
|
38
|
+
5000
|
39
|
+
end
|
40
|
+
|
41
|
+
# Generates the remote url used by Taps push/pull.
|
42
|
+
#
|
43
|
+
# ==== Parameters
|
44
|
+
#
|
45
|
+
# * <tt>:login, :password, :host, :port</tt> - See #run.
|
46
|
+
#
|
47
|
+
# ==== Examples
|
48
|
+
#
|
49
|
+
# login = fetch(:user)
|
50
|
+
# password = tmp_pass(login) # returns asdkf239udjhdaks (for example)
|
51
|
+
# remote_url(:login => login, :password => password, :host => 'load-test') # returns http://henry:asdkf239udjhdaks@load-test:5000
|
52
|
+
def remote_url(options={})
|
53
|
+
host = options[:host]
|
54
|
+
port = options[:port] || default_server_port
|
55
|
+
host += ":#{port}"
|
56
|
+
url = CapTaffy::Parse.new.uri_hash_to_url('username' => options[:login], 'password' => options[:password], 'host' => host, 'scheme' => 'http', 'path' => '')
|
57
|
+
|
58
|
+
url.sub(/\/$/, '')
|
59
|
+
end
|
60
|
+
|
61
|
+
# Generates a temporary password to be used for the Taps server command.
|
62
|
+
def tmp_pass(user)
|
63
|
+
Digest::SHA1.hexdigest("--#{Time.now.to_s}--#{user}--")
|
64
|
+
end
|
65
|
+
|
66
|
+
# A quick start for a Taps client.
|
67
|
+
#
|
68
|
+
# <tt>local_database_url</tt> and <tt>remote_url</tt> refer to the options for the Taps gem (see #run).
|
69
|
+
def taps_client(local_database_url, remote_url, &blk) # :yields: client
|
70
|
+
Taps::Config.chunksize = 1000
|
71
|
+
Taps::Config.database_url = local_database_url
|
72
|
+
Taps::Config.remote_url = remote_url
|
73
|
+
Taps::Config.verify_database_url
|
74
|
+
|
75
|
+
Taps::ClientSession.quickstart do |client|
|
76
|
+
yield client
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
# Generates the server command used to start a Taps server
|
81
|
+
#
|
82
|
+
# ==== Parameters
|
83
|
+
# * <tt>:remote_database_url, :login, :password</tt> - See #run.
|
84
|
+
# * <tt>:port</tt> - The +port+ the Taps server is on. If given and different from #default_server_port, appends <tt>--port=[port]</tt> to command.
|
85
|
+
def server_command(options={})
|
86
|
+
remote_database_url, login, password, port = options[:remote_database_url], options[:login], options[:password], options[:port]
|
87
|
+
port_argument = ''
|
88
|
+
port_argument = " --port=#{port}" if port && port != default_server_port
|
89
|
+
|
90
|
+
"taps server #{remote_database_url} #{login} #{password}#{port_argument}"
|
91
|
+
end
|
92
|
+
|
93
|
+
# The meat of the operation. Runs operations after setting up the Taps server.
|
94
|
+
#
|
95
|
+
# 1. Runs the <tt>taps</tt> taps command to start the Taps server (assuming Sinatra is running on Thin)
|
96
|
+
# 2. Wait until the server is ready
|
97
|
+
# 3. Execute block on Taps client
|
98
|
+
# 4. Close the connection(s) and bid farewell.
|
99
|
+
#
|
100
|
+
# ==== Parameters
|
101
|
+
# * <tt>:remote_database_url</tt> - Refers to local database url in the options for the Taps server command (see Taps Options).
|
102
|
+
# * <tt>:login</tt> - The login for +host+. Usually what's in <tt>set :user, "the user"</tt> in <tt>deploy.rb</tt>
|
103
|
+
# * <tt>:password</tt> - The temporary password for the Taps server.
|
104
|
+
# * <tt>:port</tt> - The +port+ the Taps server is on. If not given, defaults to #default_server_port.
|
105
|
+
# * <tt>:local_database_url</tt> - Refers to the local database url in the options for Taps client commands (see Taps Options).
|
106
|
+
#
|
107
|
+
# ==== Taps Options
|
108
|
+
#
|
109
|
+
# <tt>taps</tt>
|
110
|
+
# server <local_database_url> <login> <password> [--port=N] Start a taps database import/export server
|
111
|
+
# pull <local_database_url> <remote_url> [--chunksize=N] Pull a database from a taps server
|
112
|
+
# push <local_database_url> <remote_url> [--chunksize=N] Push a database to a taps server
|
113
|
+
#
|
114
|
+
# ==== Examples
|
115
|
+
#
|
116
|
+
# task :push do
|
117
|
+
# login = fetch(:user)
|
118
|
+
# password = Time.now.to_s
|
119
|
+
# CapTaffy.Db.run(self, { :login => login, :password => password, :remote_database_url => "sqlite://test_production", :local_database_url => "sqlite://test_development" }) do |client|
|
120
|
+
# client.cmd_send
|
121
|
+
# end
|
122
|
+
# end
|
123
|
+
def run(instance, options = {} , &blk) # :yields: client
|
124
|
+
options[:port] ||= default_server_port
|
125
|
+
remote_database_url, login, password, port, local_database_url = options[:remote_database_url], options[:login], options[:password], options[:port], options[:local_database_url]
|
126
|
+
force_local = options.delete(:local)
|
127
|
+
|
128
|
+
data_so_far = ""
|
129
|
+
instance.run CapTaffy::Db.server_command(options) do |channel, stream, data|
|
130
|
+
data_so_far << data
|
131
|
+
if data_so_far.include? ">> Listening on 0.0.0.0:#{port}, CTRL+C to stop"
|
132
|
+
host = force_local ? '127.0.0.1' : channel[:host]
|
133
|
+
remote_url = CapTaffy::Db.remote_url(options.merge(:host => host))
|
134
|
+
|
135
|
+
CapTaffy::Db.taps_client(local_database_url, remote_url) do |client|
|
136
|
+
yield client
|
137
|
+
end
|
138
|
+
|
139
|
+
data_so_far = ""
|
140
|
+
channel.close
|
141
|
+
channel[:status] = 0
|
142
|
+
end
|
143
|
+
end
|
144
|
+
end
|
145
|
+
|
146
|
+
class InvalidURL < RuntimeError # :nodoc:
|
147
|
+
end
|
148
|
+
end
|
149
|
+
|
150
|
+
Capistrano::Configuration.instance.load do
|
151
|
+
namespace :db do
|
152
|
+
# Executes given block.
|
153
|
+
# If this is a dry run, any raised exceptions will be caught and +returning+ is returned.
|
154
|
+
# If this is not a dry run, any exceptions will be raised as expected.
|
155
|
+
def dry_run_safe(returning = nil, &block) # :yields:
|
156
|
+
begin
|
157
|
+
yield
|
158
|
+
rescue Exception => e
|
159
|
+
raise e unless dry_run
|
160
|
+
return returning
|
161
|
+
end
|
162
|
+
end
|
163
|
+
|
164
|
+
task :detect, :roles => :app do
|
165
|
+
@remote_database_url = dry_run_safe('') { CapTaffy::Db.remote_database_url(self, 'production') }
|
166
|
+
@local_database_url = dry_run_safe('') { CapTaffy::Db.local_database_url('development') }
|
167
|
+
end
|
168
|
+
|
169
|
+
desc <<-DESC
|
170
|
+
Push a local database into the app's remote database.
|
171
|
+
|
172
|
+
Performs push from local development database to remote production database.
|
173
|
+
Opens a Taps server on port 5000. (Ensure port is opened on the remote server).
|
174
|
+
|
175
|
+
# alternately, specify a different port
|
176
|
+
cap db:push -s taps_port=4321
|
177
|
+
|
178
|
+
For the security conscious:
|
179
|
+
|
180
|
+
# use ssh local forwarding (ensure [port] is available on both endpoints)
|
181
|
+
ssh -N -L[port]:127.0.0.1:[port] [user]@[remote-server]
|
182
|
+
|
183
|
+
# then push locally
|
184
|
+
cap db:push -s taps_port=[port] -s local=true
|
185
|
+
DESC
|
186
|
+
task :push, :roles => :app do
|
187
|
+
detect
|
188
|
+
|
189
|
+
login = fetch(:user)
|
190
|
+
password = CapTaffy::Db.tmp_pass(login)
|
191
|
+
|
192
|
+
logger = Capistrano::Logger.new
|
193
|
+
logger.important "Auto-detected remote database: #{@remote_database_url}" if @remote_database_url != ''
|
194
|
+
logger.important "Auto-detected local database: #{@local_database_url}" if @local_database_url != ''
|
195
|
+
|
196
|
+
options = {:remote_database_url => @remote_database_url, :login => login, :password => password, :local_database_url => @local_database_url, :port => variables[:taps_port]}
|
197
|
+
options.merge!(:local => true) if variables[:local]
|
198
|
+
|
199
|
+
CapTaffy::Db.run(self, options) do |client|
|
200
|
+
client.cmd_send
|
201
|
+
end
|
202
|
+
end
|
203
|
+
|
204
|
+
desc <<-DESC
|
205
|
+
Pull the app's database into a local database.
|
206
|
+
|
207
|
+
Performs pull from remote production database to local development database.
|
208
|
+
Opens a Taps server on port 5000. (Ensure port is opened on the remote server).
|
209
|
+
|
210
|
+
# alternately, specify a different port
|
211
|
+
cap db:pull -s taps_port=4321
|
212
|
+
|
213
|
+
For the security conscious:
|
214
|
+
|
215
|
+
# use ssh local forwarding (ensure [port] is available on both endpoints)
|
216
|
+
ssh -N -L[port]:127.0.0.1:[port] [user]@[remote-server]
|
217
|
+
|
218
|
+
# then pull locally
|
219
|
+
cap db:pull -s taps_port=[port] -s local=true
|
220
|
+
DESC
|
221
|
+
task :pull, :roles => :app do
|
222
|
+
detect
|
223
|
+
|
224
|
+
login = fetch(:user)
|
225
|
+
password = CapTaffy::Db.tmp_pass(login)
|
226
|
+
|
227
|
+
logger = Capistrano::Logger.new
|
228
|
+
logger.important "Auto-detected remote database: #{@remote_database_url}" if @remote_database_url != ''
|
229
|
+
logger.important "Auto-detected local database: #{@local_database_url}" if @local_database_url != ''
|
230
|
+
|
231
|
+
options = {:remote_database_url => @remote_database_url, :login => login, :password => password, :local_database_url => @local_database_url, :port => variables[:taps_port]}
|
232
|
+
options.merge!(:local => true) if variables[:local]
|
233
|
+
|
234
|
+
CapTaffy::Db.run(self, options) do |client|
|
235
|
+
client.cmd_receive
|
236
|
+
end
|
237
|
+
end
|
238
|
+
end
|
239
|
+
end
|
@@ -0,0 +1,53 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
begin
|
3
|
+
require 'heroku'
|
4
|
+
require 'heroku/commands/base'
|
5
|
+
require 'heroku/commands/db'
|
6
|
+
rescue LoadError
|
7
|
+
error "Install the Heroku gem. On most systems this will be:\nsudo gem install taps"
|
8
|
+
end
|
9
|
+
|
10
|
+
module CapTaffy
|
11
|
+
class Parse < Heroku::Command::Db
|
12
|
+
class << self
|
13
|
+
attr_accessor :instance
|
14
|
+
|
15
|
+
# Modified from :parse_database_yml in heroku/command/db.rb
|
16
|
+
#
|
17
|
+
# Accepts a complete +db_config+ hash and +env+ and parses for a database_url accordingly.
|
18
|
+
def database_url(db_config, env)
|
19
|
+
raise Invalid, "please pass me a valid Hash loaded from a database YAML file" unless db_config
|
20
|
+
conf = db_config[env]
|
21
|
+
raise Invalid, "missing '#{env}' database in #{db_config.inspect}" unless conf
|
22
|
+
|
23
|
+
self.instance ||= CapTaffy::Parse.new
|
24
|
+
|
25
|
+
case conf['adapter']
|
26
|
+
when 'sqlite3'
|
27
|
+
return "sqlite://#{conf['database']}"
|
28
|
+
when 'postgresql'
|
29
|
+
uri_hash = self.instance.conf_to_uri_hash(conf)
|
30
|
+
uri_hash['scheme'] = 'postgres'
|
31
|
+
return self.instance.uri_hash_to_url(uri_hash)
|
32
|
+
else
|
33
|
+
return self.instance.uri_hash_to_url(self.instance.conf_to_uri_hash(conf))
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
# Override to do nothing on #new
|
39
|
+
def initialize # :nodoc:
|
40
|
+
|
41
|
+
end
|
42
|
+
|
43
|
+
# Override to pass-through on #escape
|
44
|
+
def escape(string)
|
45
|
+
string
|
46
|
+
end
|
47
|
+
|
48
|
+
public :uri_hash_to_url, :conf_to_uri_hash
|
49
|
+
|
50
|
+
class Invalid < RuntimeError # :nodoc:
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), %w[.. cap-taffy]) unless defined?(CapTaffy)
|
2
|
+
|
3
|
+
module CapTaffy::SSH
|
4
|
+
|
5
|
+
end
|
6
|
+
|
7
|
+
Capistrano::Configuration.instance.load do
|
8
|
+
namespace :ssh do
|
9
|
+
desc <<-DESC
|
10
|
+
Authorize SSH access for local computer on remote computers(s).
|
11
|
+
DESC
|
12
|
+
task :authorize do
|
13
|
+
public_key = File.read(File.expand_path(File.join(%w[~/ .ssh id_rsa.pub]))).chop
|
14
|
+
|
15
|
+
run %Q[if [ ! -f ~/.ssh/authorized_keys ]; then mkdir -p ~/.ssh && touch ~/.ssh/authorized_keys && chmod 600 ~/.ssh/authorized_keys; fi && if [ -z "$(grep "^#{public_key}$" ~/.ssh/authorized_keys)" ]; then echo "#{public_key}" >> ~/.ssh/authorized_keys && echo "Public key on '$CAPISTRANO:HOST$' authorized at '#{Time.now.to_s}'"; else echo "Public key on '$CAPISTRANO:HOST$' is already authorized."; fi]
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
data/lib/cap-taffy.rb
ADDED
@@ -0,0 +1,45 @@
|
|
1
|
+
|
2
|
+
module CapTaffy
|
3
|
+
|
4
|
+
# :stopdoc:
|
5
|
+
VERSION = '0.0.2'
|
6
|
+
LIBPATH = ::File.expand_path(::File.dirname(__FILE__)) + ::File::SEPARATOR
|
7
|
+
PATH = ::File.dirname(LIBPATH) + ::File::SEPARATOR
|
8
|
+
# :startdoc:
|
9
|
+
|
10
|
+
# Returns the version string for the library.
|
11
|
+
#
|
12
|
+
def self.version
|
13
|
+
VERSION
|
14
|
+
end
|
15
|
+
|
16
|
+
# Returns the library path for the module. If any arguments are given,
|
17
|
+
# they will be joined to the end of the libray path using
|
18
|
+
# <tt>File.join</tt>.
|
19
|
+
#
|
20
|
+
def self.libpath( *args )
|
21
|
+
args.empty? ? LIBPATH : ::File.join(LIBPATH, args.flatten)
|
22
|
+
end
|
23
|
+
|
24
|
+
# Returns the lpath for the module. If any arguments are given,
|
25
|
+
# they will be joined to the end of the path using
|
26
|
+
# <tt>File.join</tt>.
|
27
|
+
#
|
28
|
+
def self.path( *args )
|
29
|
+
args.empty? ? PATH : ::File.join(PATH, args.flatten)
|
30
|
+
end
|
31
|
+
|
32
|
+
# Utility method used to require all files ending in .rb that lie in the
|
33
|
+
# directory below this file that has the same name as the filename passed
|
34
|
+
# in. Optionally, a specific _directory_ name can be passed in such that
|
35
|
+
# the _filename_ does not have to be equivalent to the directory.
|
36
|
+
#
|
37
|
+
def self.require_all_libs_relative_to( fname, dir = nil )
|
38
|
+
dir ||= ::File.basename(fname, '.*')
|
39
|
+
search_me = ::File.expand_path(
|
40
|
+
::File.join(::File.dirname(fname), dir, '**', '*.rb'))
|
41
|
+
|
42
|
+
Dir.glob(search_me).sort.each {|rb| require rb}
|
43
|
+
end
|
44
|
+
|
45
|
+
end
|