cap-taffy 0.0.2
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.
- 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
|