dumpdb 1.0.0.rc1
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +20 -0
- data/Gemfile +6 -0
- data/LICENSE +22 -0
- data/README.md +263 -0
- data/Rakefile +8 -0
- data/dumpdb.gemspec +22 -0
- data/lib/dumpdb/db.rb +47 -0
- data/lib/dumpdb/runner.rb +76 -0
- data/lib/dumpdb/settings.rb +100 -0
- data/lib/dumpdb/version.rb +3 -0
- data/lib/dumpdb.rb +102 -0
- data/test/db_tests.rb +33 -0
- data/test/helper.rb +7 -0
- data/test/irb.rb +9 -0
- data/test/runner_tests.rb +41 -0
- data/test/script_tests.rb +130 -0
- data/test/settings_tests.rb +200 -0
- data/test/support/database.yaml +12 -0
- data/test/support/fake_cmd_runner.rb +28 -0
- data/test/support/test.yaml +6 -0
- data/test/support/test_scripts.rb +66 -0
- metadata +147 -0
data/.gitignore
ADDED
data/Gemfile
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2012-Present Kelly Redding
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,263 @@
|
|
1
|
+
# Dumpdb
|
2
|
+
|
3
|
+
Dump and restore your databases.
|
4
|
+
|
5
|
+
## Installation
|
6
|
+
|
7
|
+
Add this line to your application's Gemfile:
|
8
|
+
|
9
|
+
gem 'dumpdb'
|
10
|
+
|
11
|
+
And then execute:
|
12
|
+
|
13
|
+
$ bundle
|
14
|
+
|
15
|
+
Or install it yourself as:
|
16
|
+
|
17
|
+
$ gem install dumpdb
|
18
|
+
|
19
|
+
## Usage
|
20
|
+
|
21
|
+
```ruby
|
22
|
+
require 'dumpdb'
|
23
|
+
|
24
|
+
class MysqlFullRestore
|
25
|
+
include Dumpdb
|
26
|
+
|
27
|
+
databases { '/path/to/database.yml'}
|
28
|
+
dump_file { "dump.bz2" }
|
29
|
+
source { db('production', :output_root => '/some/source/dir') }
|
30
|
+
target { db('development', :output_root => '/some/target/dir') }
|
31
|
+
|
32
|
+
dump { "mysqldump -u :user -p\":pw\" :db | bzip2 > :dump_file" }
|
33
|
+
restore { "mysqladmin -u :user -p\":pw\" -f -b DROP :db; true" }
|
34
|
+
restore { "mysqladmin -u :user -p\":pw\" -f CREATE :db" }
|
35
|
+
restore { "bunzip2 -c :dump_file | mysql -u :user -p\":pw\" :db" }
|
36
|
+
|
37
|
+
end
|
38
|
+
```
|
39
|
+
|
40
|
+
Dumpdb provides a framework for scripting database backups and restores. You configure your source and target db settings. You define the set of commands needed for your script to dump the (local or remote) source database and optionally restore the dump to the (local) target database.
|
41
|
+
|
42
|
+
### Running
|
43
|
+
|
44
|
+
Once you have created an instance of your script with its database settings you can run it.
|
45
|
+
|
46
|
+
```ruby
|
47
|
+
MysqlFullRestore.new.run
|
48
|
+
```
|
49
|
+
|
50
|
+
Dumpdb runs the dump commands using source settings and runs the restore commands using target settings. By default, Dumpdb assumes both the dump and restore commands are to be run on the local system.
|
51
|
+
|
52
|
+
### Runner Callbacks
|
53
|
+
|
54
|
+
Dumpdb supports defining callbacks for your script. These get fired as the script is being run.
|
55
|
+
|
56
|
+
```ruby
|
57
|
+
class MysqlFullRestore
|
58
|
+
include Dumpdb
|
59
|
+
|
60
|
+
# ...
|
61
|
+
|
62
|
+
def after_dump
|
63
|
+
# this will be called after the dump commands have been run
|
64
|
+
end
|
65
|
+
|
66
|
+
end
|
67
|
+
```
|
68
|
+
|
69
|
+
Available callbacks:
|
70
|
+
|
71
|
+
* `{before|after}_run` - called before/after any commands have been executed
|
72
|
+
* `{before|after}_setup` - called before/after the runner sets up the script run
|
73
|
+
* `{before|after}_dump` - called before/after the dump cmds are executed
|
74
|
+
* `{before|after}_copy_dump` - called before/after the dump file is copied from source to target
|
75
|
+
* `{before|after}_restore` - called before/after the restore cmds are executed
|
76
|
+
* `{before|after}_teardown` - called before/after the runner tears down the script run
|
77
|
+
* `{before|after}_cmd_run` - called before/after each cmd is run, passes the cmd obj being run
|
78
|
+
|
79
|
+
Phases occur in this order: setup, dump, copy_dump, restore, teardown
|
80
|
+
|
81
|
+
### Remote dumps
|
82
|
+
|
83
|
+
To run your dump commands on a remote server, specify the optional `ssh` setting.
|
84
|
+
|
85
|
+
```ruby
|
86
|
+
class MysqlFullRestore
|
87
|
+
include Dumpdb
|
88
|
+
|
89
|
+
ssh { 'user@host' }
|
90
|
+
|
91
|
+
# ...
|
92
|
+
end
|
93
|
+
```
|
94
|
+
|
95
|
+
This tells Dumpdb to run the dump commands using ssh on a remote host and to download the dump file using sftp.
|
96
|
+
|
97
|
+
## Define your script
|
98
|
+
|
99
|
+
Every Dumpdb script assumes there are two types of commands involved: dump commands that run using source settings and restore commands that run using target settings. The dump commands should produce a single "dump file" (typically a compressed file or tar). The restore commands restore the local db from the dump file.
|
100
|
+
|
101
|
+
### The Dump File
|
102
|
+
|
103
|
+
You specify the name of the dump file using the `dump_file` setting
|
104
|
+
|
105
|
+
```ruby
|
106
|
+
# ...
|
107
|
+
dump_file { "dump.bz2" }
|
108
|
+
#...
|
109
|
+
```
|
110
|
+
|
111
|
+
This tells Dumpdb what file is being generated by the dump and will be used in the restore. The dump commands should produce it. The restore commands should use it.
|
112
|
+
|
113
|
+
### Dump commands
|
114
|
+
|
115
|
+
Dump commands are system commands that should produce the dump file.
|
116
|
+
|
117
|
+
```ruby
|
118
|
+
# ...
|
119
|
+
dump { "mysqldump -u :user -p :pw :db | bzip2 > :dump_file" }
|
120
|
+
#...
|
121
|
+
```
|
122
|
+
|
123
|
+
### Restore commands
|
124
|
+
|
125
|
+
Restore commands are system commands that should restore the local db from the dump file.
|
126
|
+
|
127
|
+
```ruby
|
128
|
+
# ...
|
129
|
+
restore { "mysqladmin -u :user :pw -f -b DROP :db; true" } # drop the local db, whether it exists or not
|
130
|
+
restore { "mysqladmin -u :user :pw -f CREATE :db" } # recreate the local db
|
131
|
+
restore { "bunzip2 -c :dump_file | mysql -u :user :pw :db" } # unzip the dump file and apply it to the db
|
132
|
+
#...
|
133
|
+
```
|
134
|
+
|
135
|
+
### Command Placeholders
|
136
|
+
|
137
|
+
Dump and restore commands are templated. You define the command with placeholders and appropriate setting values are substituted in when the script is run.
|
138
|
+
|
139
|
+
Command placeholders should correspond with keys in the source or target settings. Dump commands use the source settings and restore commands use the target settings.
|
140
|
+
|
141
|
+
### Special Placeholders
|
142
|
+
|
143
|
+
There are two special placeholders that are added to the source and target settings automatically:
|
144
|
+
|
145
|
+
* `:output_dir`
|
146
|
+
dir the dump file is written to or read from (depending on whether dumping or restoring). This is generated by the script instance. By default, no specific root value is used - pass in a `:output_root` value to the source and target to specify one.
|
147
|
+
|
148
|
+
* `:dump_file`
|
149
|
+
path of the dump file - uses the :output_dir setting
|
150
|
+
|
151
|
+
You should at least use the `:dump_file` placeholder in your dump and restore commands to ensure proper dump handling and usage.
|
152
|
+
|
153
|
+
```ruby
|
154
|
+
dump_file { "dump.bz2" }
|
155
|
+
|
156
|
+
dump { "mysqldump :db | bzip2 > :dump_file" }
|
157
|
+
restore { "bunzip2 -c :dump_file | mysql :db" }
|
158
|
+
```
|
159
|
+
|
160
|
+
## Source / Target settings
|
161
|
+
|
162
|
+
A Dumpdb script needs to be told about its source and target settings. You tell it these when you define your script:
|
163
|
+
|
164
|
+
```ruby
|
165
|
+
class MysqlFullRestore
|
166
|
+
include Dumpdb
|
167
|
+
|
168
|
+
source do
|
169
|
+
{ 'user' => 'something',
|
170
|
+
'pw' => 'secret',
|
171
|
+
'db' => 'something_production',
|
172
|
+
'something' => 'else'
|
173
|
+
}
|
174
|
+
end
|
175
|
+
|
176
|
+
target do
|
177
|
+
{ 'user' => 'root',
|
178
|
+
'pw' => 'supersecret',
|
179
|
+
'db' => 'something_development'
|
180
|
+
}
|
181
|
+
end
|
182
|
+
|
183
|
+
# ...
|
184
|
+
end
|
185
|
+
```
|
186
|
+
|
187
|
+
Any settings keys can be used as command placeholders in dump and restore commands.
|
188
|
+
|
189
|
+
**Note:** When reading source and target settings, Dumpdb takes common keys like 'hostname', 'username', 'password', and 'database' and exposes them with the more succinct 'host', 'user', 'pw', and 'db'.
|
190
|
+
|
191
|
+
### Lookup settings from YAML
|
192
|
+
|
193
|
+
Since many ORMs allow you to configure db connections using yaml files, Dumpdb supports specifying your databases from a yaml file.
|
194
|
+
|
195
|
+
```ruby
|
196
|
+
class MysqlFullRestore
|
197
|
+
include Dumpdb
|
198
|
+
|
199
|
+
databases { '/path/to/database.yml' }
|
200
|
+
|
201
|
+
# ...
|
202
|
+
end
|
203
|
+
```
|
204
|
+
|
205
|
+
Now you can lookup your source and target settings using the `db` method.
|
206
|
+
|
207
|
+
```ruby
|
208
|
+
databases { '/path/to/database.yml' }
|
209
|
+
source { db('production') }
|
210
|
+
target { db('development') }
|
211
|
+
```
|
212
|
+
|
213
|
+
You can merge in additional settings by passing them to the `db` command:
|
214
|
+
|
215
|
+
```ruby
|
216
|
+
class MysqlFullRestore
|
217
|
+
include Dumpdb
|
218
|
+
|
219
|
+
databases { '/path/to/database.yml' }
|
220
|
+
source { db('produciton', :something => 'else') }
|
221
|
+
|
222
|
+
# ...
|
223
|
+
end
|
224
|
+
```
|
225
|
+
|
226
|
+
### Building Commands
|
227
|
+
|
228
|
+
As you may have noticed, the script DSL settings methods all take a proc as their argument. This is because the procs are lazy-eval'd in the scope of the script instance. This allows you to use interpolation to help build commands with dynamic data.
|
229
|
+
|
230
|
+
Take this example where you want your dump script to honor ignored tables.
|
231
|
+
|
232
|
+
```ruby
|
233
|
+
require 'dumpdb'
|
234
|
+
|
235
|
+
class MysqlIgnoredTablesRestore
|
236
|
+
include Dumpdb
|
237
|
+
|
238
|
+
# ...
|
239
|
+
dump { "mysqldump -u :user -p :pw :db #{ignored_tables} | bzip2 > :dump_file" }
|
240
|
+
# ...
|
241
|
+
|
242
|
+
def initialize(opts={})
|
243
|
+
opts[:ignored_tables] ||= []
|
244
|
+
@opts = opts
|
245
|
+
end
|
246
|
+
|
247
|
+
def ignored_tables
|
248
|
+
@opts[:ignored_tables].collect {|t| "--ignore-table=#{source.db}.#{t}"}.join(' ')
|
249
|
+
end
|
250
|
+
end
|
251
|
+
```
|
252
|
+
|
253
|
+
## Examples
|
254
|
+
|
255
|
+
See `examples/` dir. (TODO)
|
256
|
+
|
257
|
+
## Contributing
|
258
|
+
|
259
|
+
1. Fork it
|
260
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
261
|
+
3. Commit your changes (`git commit -am 'Added some feature'`)
|
262
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
263
|
+
5. Create new Pull Request
|
data/Rakefile
ADDED
data/dumpdb.gemspec
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
require File.expand_path('../lib/dumpdb/version', __FILE__)
|
3
|
+
|
4
|
+
Gem::Specification.new do |gem|
|
5
|
+
gem.name = "dumpdb"
|
6
|
+
gem.version = Dumpdb::VERSION
|
7
|
+
gem.description = %q{Dump and restore your databases.}
|
8
|
+
gem.summary = %q{Dump and restore your databases.}
|
9
|
+
|
10
|
+
gem.authors = ["Kelly Redding", "Collin Redding"]
|
11
|
+
gem.email = ["kelly@kellyredding.com", "collin.redding@me.com"]
|
12
|
+
gem.homepage = "http://github.com/redding/dumpdb"
|
13
|
+
|
14
|
+
gem.files = `git ls-files`.split("\n")
|
15
|
+
gem.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
16
|
+
gem.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
17
|
+
gem.require_paths = ["lib"]
|
18
|
+
|
19
|
+
gem.add_development_dependency("assert")
|
20
|
+
gem.add_dependency("scmd", ["~>2.0"])
|
21
|
+
gem.add_dependency("ns-options", ["1.0.0.rc1"])
|
22
|
+
end
|
data/lib/dumpdb/db.rb
ADDED
@@ -0,0 +1,47 @@
|
|
1
|
+
require 'ostruct'
|
2
|
+
|
3
|
+
module Dumpdb
|
4
|
+
|
5
|
+
class Db
|
6
|
+
|
7
|
+
def initialize(dump_file_name, values=nil)
|
8
|
+
@dump_file_name = dump_file_name || 'dump.output'
|
9
|
+
@values = (values || {}).inject({}) do |vals, (k, v)|
|
10
|
+
# stringify keys
|
11
|
+
vals.merge(k.to_s => v)
|
12
|
+
end
|
13
|
+
|
14
|
+
@values['host'] ||= (@values['hostname'] || '')
|
15
|
+
@values['user'] ||= (@values['username'] || '')
|
16
|
+
@values['pw'] ||= (@values['password'] || '')
|
17
|
+
@values['db'] ||= (@values['database'] || '')
|
18
|
+
@values['output_root'] ||= ''
|
19
|
+
|
20
|
+
@values['output_dir'] = output_dir(self.output_root, "#{self.host}__#{self.db}")
|
21
|
+
@values['dump_file'] = File.join(self.output_dir, @dump_file_name)
|
22
|
+
end
|
23
|
+
|
24
|
+
def to_hash; @values; end
|
25
|
+
|
26
|
+
def method_missing(meth, *args, &block)
|
27
|
+
if @values.has_key?(meth.to_s)
|
28
|
+
@values[meth.to_s]
|
29
|
+
else
|
30
|
+
super
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
def respond_to?(meth)
|
35
|
+
@values.has_key?(meth.to_s) || super
|
36
|
+
end
|
37
|
+
|
38
|
+
private
|
39
|
+
|
40
|
+
def output_dir(root, name)
|
41
|
+
name_time = "#{name}__#{Time.now.to_f}"
|
42
|
+
root && !root.empty? ? File.join(root, name_time) : name_time
|
43
|
+
end
|
44
|
+
|
45
|
+
end
|
46
|
+
|
47
|
+
end
|
@@ -0,0 +1,76 @@
|
|
1
|
+
require 'dumpdb/settings'
|
2
|
+
|
3
|
+
module Dumpdb
|
4
|
+
class Runner
|
5
|
+
|
6
|
+
attr_reader :script, :cmd_runner
|
7
|
+
|
8
|
+
def initialize(script, opts={})
|
9
|
+
@script = script
|
10
|
+
@cmd_runner = opts[:cmd_runner] || scmd_cmd_runner
|
11
|
+
end
|
12
|
+
|
13
|
+
def run
|
14
|
+
run_callback 'before_run'
|
15
|
+
run_callback 'before_setup'
|
16
|
+
run_setup
|
17
|
+
|
18
|
+
begin
|
19
|
+
run_callback 'after_setup'
|
20
|
+
[:dump, :copy_dump, :restore].each{|phase_name| run_phase phase_name}
|
21
|
+
ensure
|
22
|
+
run_phase 'teardown'
|
23
|
+
run_callback 'after_run'
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
protected
|
28
|
+
|
29
|
+
def run_setup
|
30
|
+
run_cmd(@script.dump_cmd { "mkdir -p #{source.output_dir}" })
|
31
|
+
run_cmd(@script.restore_cmd { "mkdir -p #{target.output_dir}" })
|
32
|
+
end
|
33
|
+
|
34
|
+
def run_dump
|
35
|
+
@script.dump_cmds.each{|cmd| run_cmd(cmd)}
|
36
|
+
end
|
37
|
+
|
38
|
+
def run_copy_dump
|
39
|
+
run_cmd @script.copy_dump_cmd
|
40
|
+
end
|
41
|
+
|
42
|
+
def run_restore
|
43
|
+
@script.restore_cmds.each{|cmd| run_cmd(cmd)}
|
44
|
+
end
|
45
|
+
|
46
|
+
def run_teardown
|
47
|
+
run_cmd(@script.dump_cmd { "rm -rf #{source.output_dir}" })
|
48
|
+
run_cmd(@script.restore_cmd { "rm -rf #{target.output_dir}" })
|
49
|
+
end
|
50
|
+
|
51
|
+
private
|
52
|
+
|
53
|
+
def run_phase(phase_name)
|
54
|
+
run_callback "before_#{phase_name}"
|
55
|
+
self.send("run_#{phase_name}")
|
56
|
+
run_callback "after_#{phase_name}"
|
57
|
+
end
|
58
|
+
|
59
|
+
def run_cmd(cmd_str)
|
60
|
+
cmd_obj = @cmd_runner.new(cmd_str)
|
61
|
+
run_callback('before_cmd_run', cmd_obj)
|
62
|
+
cmd_obj.run!
|
63
|
+
run_callback('after_cmd_run', cmd_obj)
|
64
|
+
end
|
65
|
+
|
66
|
+
def run_callback(meth, *args)
|
67
|
+
@script.send(meth.to_s, *args)
|
68
|
+
end
|
69
|
+
|
70
|
+
def scmd_cmd_runner
|
71
|
+
require 'scmd'
|
72
|
+
Scmd
|
73
|
+
end
|
74
|
+
|
75
|
+
end
|
76
|
+
end
|
@@ -0,0 +1,100 @@
|
|
1
|
+
require 'dumpdb/db'
|
2
|
+
|
3
|
+
module Dumpdb::Settings
|
4
|
+
|
5
|
+
class Base
|
6
|
+
|
7
|
+
attr_reader :proc
|
8
|
+
|
9
|
+
def initialize(proc=nil)
|
10
|
+
@proc = proc.kind_of?(::Proc) ? proc : Proc.new { proc }
|
11
|
+
end
|
12
|
+
|
13
|
+
def value(script)
|
14
|
+
script.instance_eval &@proc
|
15
|
+
end
|
16
|
+
|
17
|
+
end
|
18
|
+
|
19
|
+
class Ssh < Base; end
|
20
|
+
|
21
|
+
class Databases < Base
|
22
|
+
|
23
|
+
def value(script)
|
24
|
+
val = super
|
25
|
+
val.kind_of?(::String) ? load_yaml(val) : val
|
26
|
+
end
|
27
|
+
|
28
|
+
private
|
29
|
+
|
30
|
+
def load_yaml(file_path)
|
31
|
+
YAML.load(File.read(File.expand_path(file_path)))
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
class DumpFile < Base; end
|
36
|
+
|
37
|
+
class SourceTarget < Base
|
38
|
+
|
39
|
+
def value(script)
|
40
|
+
val = super
|
41
|
+
val.kind_of?(Dumpdb::Db) ? val : Dumpdb::Db.new(script.dump_file, val)
|
42
|
+
end
|
43
|
+
|
44
|
+
end
|
45
|
+
|
46
|
+
class Cmd < Base
|
47
|
+
|
48
|
+
def value(script, placeholder_vals)
|
49
|
+
hsub(super(script), placeholder_vals)
|
50
|
+
end
|
51
|
+
|
52
|
+
private
|
53
|
+
|
54
|
+
def hsub(string, hash)
|
55
|
+
hash.inject(string) {|new_str, (k, v)| new_str.gsub(":#{k}", v.to_s)}
|
56
|
+
end
|
57
|
+
|
58
|
+
end
|
59
|
+
|
60
|
+
class DumpCmd < Cmd
|
61
|
+
|
62
|
+
def value(script, placeholder_vals={})
|
63
|
+
val = super(script, script.source.to_hash.merge(placeholder_vals))
|
64
|
+
if script.ssh?
|
65
|
+
val = "ssh -A #{script.ssh_opts} #{script.ssh} \"#{val}\""
|
66
|
+
end
|
67
|
+
val
|
68
|
+
end
|
69
|
+
|
70
|
+
end
|
71
|
+
|
72
|
+
class RestoreCmd < Cmd
|
73
|
+
|
74
|
+
def value(script, placeholder_vals={})
|
75
|
+
super(script, script.target.to_hash.merge(placeholder_vals))
|
76
|
+
end
|
77
|
+
|
78
|
+
end
|
79
|
+
|
80
|
+
class CopyDumpCmd < Cmd
|
81
|
+
|
82
|
+
def value(script)
|
83
|
+
if script.ssh?
|
84
|
+
"sftp #{script.ssh_opts} #{script.ssh}:#{script.source.dump_file} #{script.target.dump_file}"
|
85
|
+
else
|
86
|
+
"cp #{script.source.dump_file} #{script.target.dump_file}"
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
end
|
91
|
+
|
92
|
+
class CmdList < ::Array
|
93
|
+
|
94
|
+
def value(script, placeholder_vals={})
|
95
|
+
self.map{|cmd| cmd.value(script, placeholder_vals)}
|
96
|
+
end
|
97
|
+
|
98
|
+
end
|
99
|
+
|
100
|
+
end
|
data/lib/dumpdb.rb
ADDED
@@ -0,0 +1,102 @@
|
|
1
|
+
require 'ns-options'
|
2
|
+
|
3
|
+
require 'dumpdb/settings'
|
4
|
+
require 'dumpdb/db'
|
5
|
+
require 'dumpdb/runner'
|
6
|
+
|
7
|
+
module Dumpdb
|
8
|
+
|
9
|
+
class BadDatabaseName < RuntimeError; end
|
10
|
+
|
11
|
+
def self.included(receiver)
|
12
|
+
receiver.class_eval do
|
13
|
+
include NsOptions
|
14
|
+
options :settings do
|
15
|
+
option 'ssh', Settings::Ssh, :default => ''
|
16
|
+
option 'databases', Settings::Databases, :default => {}
|
17
|
+
option 'dump_file', Settings::DumpFile, :default => ''
|
18
|
+
option 'source', Settings::SourceTarget, :default => {}
|
19
|
+
option 'target', Settings::SourceTarget, :default => {}
|
20
|
+
option 'dump_cmds', Settings::CmdList, :default => []
|
21
|
+
option 'restore_cmds', Settings::CmdList, :default => []
|
22
|
+
end
|
23
|
+
|
24
|
+
extend SettingsDslMethods
|
25
|
+
include SettingsMethods
|
26
|
+
|
27
|
+
def self.inherited(subclass)
|
28
|
+
subclass.settings.apply(self.settings.to_hash)
|
29
|
+
end
|
30
|
+
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
module SettingsDslMethods
|
35
|
+
|
36
|
+
def ssh(&block); settings.ssh = Settings::Ssh.new(block); end
|
37
|
+
def databases(&block); settings.databases = Settings::Databases.new(block); end
|
38
|
+
def dump_file(&block); settings.dump_file = Settings::DumpFile.new(block); end
|
39
|
+
def source(&block); settings.source = Settings::SourceTarget.new(block); end
|
40
|
+
def target(&block); settings.target = Settings::SourceTarget.new(block); end
|
41
|
+
|
42
|
+
def dump(&block); settings.dump_cmds << Settings::DumpCmd.new(block); end
|
43
|
+
def restore(&block); settings.restore_cmds << Settings::RestoreCmd.new(block); end
|
44
|
+
|
45
|
+
end
|
46
|
+
|
47
|
+
module SettingsMethods
|
48
|
+
|
49
|
+
def settings; self.class.settings; end
|
50
|
+
|
51
|
+
def ssh; @ssh ||= settings.ssh.value(self); end
|
52
|
+
def databases; @databases ||= settings.databases.value(self); end
|
53
|
+
def dump_file; @dump_file ||= settings.dump_file.value(self); end
|
54
|
+
def source; @source ||= settings.source.value(self); end
|
55
|
+
def target; @target ||= settings.target.value(self); end
|
56
|
+
|
57
|
+
def dump_cmds; @dump_cmds ||= settings.dump_cmds.value(self); end
|
58
|
+
def restore_cmds; @restore_cmds ||= settings.restore_cmds.value(self); end
|
59
|
+
def copy_dump_cmd; @copy_dump_cmd ||= Settings::CopyDumpCmd.new.value(self); end
|
60
|
+
|
61
|
+
end
|
62
|
+
|
63
|
+
def db(database_name, other_vals=nil)
|
64
|
+
if (db_vals = self.databases[database_name]).nil?
|
65
|
+
raise BadDatabaseName, "no database named `#{database_name}'."
|
66
|
+
end
|
67
|
+
Db.new(self.dump_file, db_vals.merge(other_vals || {}))
|
68
|
+
end
|
69
|
+
|
70
|
+
def dump_cmd(&block); Settings::DumpCmd.new(block).value(self); end
|
71
|
+
def restore_cmd(&block) Settings::RestoreCmd.new(block).value(self); end
|
72
|
+
|
73
|
+
def ssh?
|
74
|
+
self.ssh && !self.ssh.empty?
|
75
|
+
end
|
76
|
+
|
77
|
+
def ssh_opts
|
78
|
+
"-o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no -o ConnectTimeout=10"
|
79
|
+
end
|
80
|
+
|
81
|
+
def run(cmd_runner=nil)
|
82
|
+
Runner.new(self, :cmd_runner => cmd_runner).run
|
83
|
+
end
|
84
|
+
|
85
|
+
# Callbacks
|
86
|
+
|
87
|
+
def before_run(*args); end
|
88
|
+
def after_run(*args); end
|
89
|
+
def before_setup(*args); end
|
90
|
+
def after_setup(*args); end
|
91
|
+
def before_dump(*args); end
|
92
|
+
def after_dump(*args); end
|
93
|
+
def before_copy_dump(*args); end
|
94
|
+
def after_copy_dump(*args); end
|
95
|
+
def before_restore(*args); end
|
96
|
+
def after_restore(*args); end
|
97
|
+
def before_teardown(*args); end
|
98
|
+
def after_teardown(*args); end
|
99
|
+
def before_cmd_run(*args); end
|
100
|
+
def after_cmd_run(*args); end
|
101
|
+
|
102
|
+
end
|
data/test/db_tests.rb
ADDED
@@ -0,0 +1,33 @@
|
|
1
|
+
require 'assert'
|
2
|
+
require 'ostruct'
|
3
|
+
|
4
|
+
module Dumpdb
|
5
|
+
|
6
|
+
class DbTests < Assert::Context
|
7
|
+
desc "the Db helper class"
|
8
|
+
setup do
|
9
|
+
@db = Db.new(nil)#(:host => 'h', :user => 'u', :pw => 'p', :db => 'd')
|
10
|
+
end
|
11
|
+
subject { @db }
|
12
|
+
|
13
|
+
should have_imeths :host, :user, :pw, :db, :output_root, :output_dir, :dump_file
|
14
|
+
|
15
|
+
should "default its values" do
|
16
|
+
[:host, :user, :pw, :db, :output_root].each do |val|
|
17
|
+
assert_equal '', subject.send(val)
|
18
|
+
end
|
19
|
+
assert_match '____', subject.output_dir
|
20
|
+
assert_match 'dump.output', subject.dump_file
|
21
|
+
end
|
22
|
+
|
23
|
+
should "set values" do
|
24
|
+
db = Db.new('dump.file', :host => 'h', :db => 'd', :something => 'else')
|
25
|
+
|
26
|
+
assert_equal 'h', db.host
|
27
|
+
assert_equal 'd', db.db
|
28
|
+
assert_match 'h__d__', db.output_dir
|
29
|
+
assert_match 'dump.file', db.dump_file
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
end
|
data/test/helper.rb
ADDED
data/test/irb.rb
ADDED
@@ -0,0 +1,41 @@
|
|
1
|
+
require 'assert'
|
2
|
+
require 'test/support/fake_cmd_runner'
|
3
|
+
|
4
|
+
require 'dumpdb/runner'
|
5
|
+
|
6
|
+
module Dumpdb
|
7
|
+
|
8
|
+
class RunnerTests < Assert::Context
|
9
|
+
desc "the runner"
|
10
|
+
setup do
|
11
|
+
FakeCmdRunner.reset
|
12
|
+
@script = RunnerScript.new
|
13
|
+
@runner = Runner.new(@script, :cmd_runner => FakeCmdRunner)
|
14
|
+
end
|
15
|
+
teardown do
|
16
|
+
FakeCmdRunner.reset
|
17
|
+
end
|
18
|
+
subject { @runner }
|
19
|
+
|
20
|
+
|
21
|
+
should have_reader :script, :cmd_runner
|
22
|
+
|
23
|
+
should "run the script" do
|
24
|
+
assert_empty FakeCmdRunner.cmds
|
25
|
+
subject.run
|
26
|
+
|
27
|
+
assert_not_empty FakeCmdRunner.cmds
|
28
|
+
assert_equal 7, FakeCmdRunner.cmds.size
|
29
|
+
assert_equal "a restore cmd", FakeCmdRunner.cmds[-3]
|
30
|
+
end
|
31
|
+
|
32
|
+
should "call the callbacks" do
|
33
|
+
assert_not @script.all_callbacks_called?
|
34
|
+
subject.run
|
35
|
+
|
36
|
+
assert @script.all_callbacks_called?
|
37
|
+
end
|
38
|
+
|
39
|
+
end
|
40
|
+
|
41
|
+
end
|
@@ -0,0 +1,130 @@
|
|
1
|
+
require 'assert'
|
2
|
+
|
3
|
+
module Dumpdb
|
4
|
+
|
5
|
+
class ScriptTests < Assert::Context
|
6
|
+
desc "the main script mixin"
|
7
|
+
setup do
|
8
|
+
@script = LocalScript.new
|
9
|
+
end
|
10
|
+
subject { @script }
|
11
|
+
|
12
|
+
should have_cmeths :settings
|
13
|
+
should have_imeths :settings, :db, :dump_cmd, :restore_cmd, :ssh?, :ssh_opts, :run
|
14
|
+
|
15
|
+
should have_cmeths :ssh, :databases, :dump_file, :source, :target
|
16
|
+
should have_imeths :ssh, :databases, :dump_file, :source, :target
|
17
|
+
|
18
|
+
should have_cmeths :dump, :restore
|
19
|
+
should have_imeths :dump_cmds, :restore_cmds, :copy_dump_cmd
|
20
|
+
|
21
|
+
should have_imeths :before_run, :before_setup, :before_teardown
|
22
|
+
should have_imeths :after_run, :after_setup, :after_teardown
|
23
|
+
should have_imeths :before_dump, :before_copy_dump, :before_restore
|
24
|
+
should have_imeths :after_dump, :after_copy_dump, :after_restore
|
25
|
+
|
26
|
+
should "store its settings using ns-options" do
|
27
|
+
assert_kind_of NsOptions::Namespace, subject.class.settings
|
28
|
+
assert_same subject.class.settings, subject.settings
|
29
|
+
end
|
30
|
+
|
31
|
+
should "store off the settings for the script" do
|
32
|
+
assert_kind_of Settings::Ssh, subject.settings.ssh
|
33
|
+
assert_kind_of Settings::Databases, subject.settings.databases
|
34
|
+
assert_kind_of Settings::DumpFile, subject.settings.dump_file
|
35
|
+
assert_kind_of Settings::SourceTarget, subject.settings.source
|
36
|
+
assert_kind_of Settings::SourceTarget, subject.settings.target
|
37
|
+
assert_kind_of Settings::CmdList, subject.settings.dump_cmds
|
38
|
+
assert_kind_of Settings::CmdList, subject.settings.restore_cmds
|
39
|
+
end
|
40
|
+
|
41
|
+
end
|
42
|
+
|
43
|
+
class DbMethTests < ScriptTests
|
44
|
+
desc "`db' method"
|
45
|
+
setup do
|
46
|
+
@script = LocalScript.new
|
47
|
+
end
|
48
|
+
|
49
|
+
should "build a Db based on the named database values" do
|
50
|
+
assert_kind_of Db, subject.target
|
51
|
+
assert_equal 'testhost', subject.target.host
|
52
|
+
end
|
53
|
+
|
54
|
+
should "build a Db based on the named database values plus additional values" do
|
55
|
+
assert_kind_of Db, subject.source
|
56
|
+
assert_equal 'devhost', subject.source.host
|
57
|
+
assert_equal 'value', subject.source.another
|
58
|
+
end
|
59
|
+
|
60
|
+
should "complain if looking up a db not in the `databases` collection" do
|
61
|
+
assert_raises BadDatabaseName do
|
62
|
+
subject.db('does_not_exist')
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
end
|
67
|
+
|
68
|
+
class CmdMethsTests < ScriptTests
|
69
|
+
|
70
|
+
should "build dump command strings" do
|
71
|
+
assert_equal 'echo local', subject.dump_cmd { "echo #{type}" }
|
72
|
+
end
|
73
|
+
|
74
|
+
should "build restore command strings" do
|
75
|
+
assert_equal 'echo local', subject.restore_cmd { "echo #{type}" }
|
76
|
+
end
|
77
|
+
|
78
|
+
end
|
79
|
+
|
80
|
+
class SshTests < ScriptTests
|
81
|
+
|
82
|
+
should "know if its in ssh mode or not" do
|
83
|
+
assert RemoteScript.new.ssh?
|
84
|
+
assert_not LocalScript.new.ssh?
|
85
|
+
end
|
86
|
+
|
87
|
+
should "know what ssh options to use" do
|
88
|
+
exp_opts = "-o UserKnownHostsFile=/dev/null"\
|
89
|
+
" -o StrictHostKeyChecking=no"\
|
90
|
+
" -o ConnectTimeout=10"\
|
91
|
+
|
92
|
+
assert_equal exp_opts, subject.ssh_opts
|
93
|
+
end
|
94
|
+
|
95
|
+
end
|
96
|
+
|
97
|
+
class RunTests < ScriptTests
|
98
|
+
setup do
|
99
|
+
FakeCmdRunner.reset
|
100
|
+
@script = RunnerScript.new
|
101
|
+
end
|
102
|
+
teardown do
|
103
|
+
FakeCmdRunner.reset
|
104
|
+
end
|
105
|
+
|
106
|
+
should "run the script when `run` is called" do
|
107
|
+
assert_empty FakeCmdRunner.cmds
|
108
|
+
@script.run(FakeCmdRunner)
|
109
|
+
|
110
|
+
assert_not_empty FakeCmdRunner.cmds
|
111
|
+
assert_equal 7, FakeCmdRunner.cmds.size
|
112
|
+
assert_equal "a restore cmd", FakeCmdRunner.cmds[-3]
|
113
|
+
end
|
114
|
+
|
115
|
+
end
|
116
|
+
|
117
|
+
class InheritedTests < ScriptTests
|
118
|
+
desc "when inherited"
|
119
|
+
setup do
|
120
|
+
@a_remote_script = RemoteScript.new
|
121
|
+
@a_sub_remote_script = Class.new(RemoteScript).new
|
122
|
+
end
|
123
|
+
|
124
|
+
should "pass its definition values to any subclass" do
|
125
|
+
assert_equal @a_remote_script.ssh, @a_sub_remote_script.ssh
|
126
|
+
end
|
127
|
+
|
128
|
+
end
|
129
|
+
|
130
|
+
end
|
@@ -0,0 +1,200 @@
|
|
1
|
+
require 'assert'
|
2
|
+
|
3
|
+
require 'dumpdb/settings'
|
4
|
+
|
5
|
+
module Dumpdb
|
6
|
+
|
7
|
+
class SettingsTests < Assert::Context
|
8
|
+
desc "the script settings"
|
9
|
+
setup do
|
10
|
+
@setting = Settings::Base.new
|
11
|
+
@script = LocalScript.new
|
12
|
+
end
|
13
|
+
subject { @setting }
|
14
|
+
|
15
|
+
should have_imeth :value
|
16
|
+
should have_reader :proc
|
17
|
+
|
18
|
+
should "know its value proc" do
|
19
|
+
assert_kind_of ::Proc, subject.proc
|
20
|
+
assert_nil subject.proc.call
|
21
|
+
end
|
22
|
+
|
23
|
+
should "instance eval its proc in the scope of a script to return a value" do
|
24
|
+
setting = Settings::Base.new(Proc.new { "something: #{type}"})
|
25
|
+
|
26
|
+
assert_equal "local", @script.type
|
27
|
+
assert_equal "something: local", setting.value(@script)
|
28
|
+
end
|
29
|
+
|
30
|
+
end
|
31
|
+
|
32
|
+
class SshSettingTests < SettingsTests
|
33
|
+
desc "`ssh` setting"
|
34
|
+
|
35
|
+
should "be available" do
|
36
|
+
assert Settings::Ssh
|
37
|
+
end
|
38
|
+
|
39
|
+
end
|
40
|
+
|
41
|
+
class DatabasesSettingTests < SettingsTests
|
42
|
+
desc "`databases` setting"
|
43
|
+
setup do
|
44
|
+
@from_hash = {
|
45
|
+
'db1' => {'db' => 'one'},
|
46
|
+
'db2' => {'db' => 'two'},
|
47
|
+
}
|
48
|
+
end
|
49
|
+
|
50
|
+
should "be available" do
|
51
|
+
assert Settings::Databases
|
52
|
+
end
|
53
|
+
|
54
|
+
should "come from a hash" do
|
55
|
+
databases = Settings::Databases.new(@from_hash)
|
56
|
+
assert_equal @from_hash, databases.value(@script)
|
57
|
+
end
|
58
|
+
|
59
|
+
should "come from a yaml file" do
|
60
|
+
databases = Settings::Databases.new('test/support/test.yaml')
|
61
|
+
assert_equal({
|
62
|
+
'db-one' => {'db' => 1},
|
63
|
+
'db-two' => {'db' => 2},
|
64
|
+
}, databases.value(@script))
|
65
|
+
end
|
66
|
+
|
67
|
+
end
|
68
|
+
|
69
|
+
class DumpFileSettingTests < SettingsTests
|
70
|
+
desc "`dump_file` setting"
|
71
|
+
|
72
|
+
should "be available" do
|
73
|
+
assert Settings::DumpFile
|
74
|
+
end
|
75
|
+
|
76
|
+
end
|
77
|
+
|
78
|
+
class SourceTargetSettingTests < SettingsTests
|
79
|
+
desc "`source` or `target` setting"
|
80
|
+
setup do
|
81
|
+
@from_hash = {'host' => 'from_hash'}
|
82
|
+
end
|
83
|
+
|
84
|
+
should "be available" do
|
85
|
+
assert Settings::SourceTarget
|
86
|
+
end
|
87
|
+
|
88
|
+
should "come from a hash" do
|
89
|
+
db = Settings::SourceTarget.new(@from_hash).value(@script)
|
90
|
+
|
91
|
+
assert_kind_of Db, db
|
92
|
+
assert_equal 'from_hash', db.host
|
93
|
+
end
|
94
|
+
|
95
|
+
should "come from a Db obj" do
|
96
|
+
db = Settings::Databases.new(Db.new('dump.file', {'host' => 'from_db'})).value(@script)
|
97
|
+
|
98
|
+
assert_kind_of Db, db
|
99
|
+
assert_equal 'from_db', db.host
|
100
|
+
end
|
101
|
+
|
102
|
+
end
|
103
|
+
|
104
|
+
class CmdTests < SettingsTests
|
105
|
+
desc "command helper class"
|
106
|
+
setup do
|
107
|
+
@cmd_str = Proc.new { "this is the #{type} db: :db" }
|
108
|
+
end
|
109
|
+
|
110
|
+
should "be available" do
|
111
|
+
assert Settings::Cmd
|
112
|
+
end
|
113
|
+
|
114
|
+
should "eval and apply any placeholders to the cmd string" do
|
115
|
+
cmd_val = Settings::Cmd.new(@cmd_str).value(@script, @script.source.to_hash)
|
116
|
+
assert_equal "this is the local db: devdb", cmd_val
|
117
|
+
end
|
118
|
+
|
119
|
+
end
|
120
|
+
|
121
|
+
class DumpCmdTests < CmdTests
|
122
|
+
desc "for dump commands"
|
123
|
+
|
124
|
+
should "eval and apply any source placeholders to the cmd string" do
|
125
|
+
cmd_val = Settings::DumpCmd.new(@cmd_str).value(@script)
|
126
|
+
assert_equal "this is the local db: devdb", cmd_val
|
127
|
+
end
|
128
|
+
|
129
|
+
end
|
130
|
+
|
131
|
+
class RemoteDumpCmdTests < DumpCmdTests
|
132
|
+
desc "using ssh"
|
133
|
+
setup do
|
134
|
+
@script = RemoteScript.new
|
135
|
+
@cmd_str = Proc.new { "echo hello" }
|
136
|
+
end
|
137
|
+
|
138
|
+
should "build the cmds to run remtoely using ssh" do
|
139
|
+
exp_cmd_str = "ssh -A #{@script.ssh_opts} #{@script.ssh} \"echo hello\""
|
140
|
+
cmd_val = Settings::DumpCmd.new(@cmd_str).value(@script)
|
141
|
+
|
142
|
+
assert_equal exp_cmd_str, cmd_val
|
143
|
+
end
|
144
|
+
|
145
|
+
end
|
146
|
+
|
147
|
+
class RestoreCmdTests < CmdTests
|
148
|
+
desc "for restore commands"
|
149
|
+
|
150
|
+
should "eval and apply any target placeholders to the cmd string" do
|
151
|
+
cmd_val = Settings::RestoreCmd.new(@cmd_str).value(@script)
|
152
|
+
assert_equal "this is the local db: testdb", cmd_val
|
153
|
+
end
|
154
|
+
|
155
|
+
end
|
156
|
+
|
157
|
+
class CopyDumpCmdTests < CmdTests
|
158
|
+
|
159
|
+
should "be a copy cmd for non-ssh scripts" do
|
160
|
+
script = @script
|
161
|
+
exp_cmd = "cp #{script.source.dump_file} #{script.target.dump_file}"
|
162
|
+
|
163
|
+
assert_equal exp_cmd, script.copy_dump_cmd
|
164
|
+
end
|
165
|
+
|
166
|
+
should "be an sftp cmd for ssh scripts" do
|
167
|
+
script = RemoteScript.new
|
168
|
+
exp_cmd = "sftp #{script.ssh_opts} #{script.ssh}:#{script.source.dump_file} #{script.target.dump_file}"
|
169
|
+
|
170
|
+
assert_equal exp_cmd, script.copy_dump_cmd
|
171
|
+
end
|
172
|
+
|
173
|
+
end
|
174
|
+
|
175
|
+
class CmdListTests < SettingsTests
|
176
|
+
desc "command list helper class"
|
177
|
+
setup do
|
178
|
+
@cmds = [
|
179
|
+
Settings::Cmd.new(Proc.new { "this is the #{type} target db: :db" }),
|
180
|
+
Settings::Cmd.new(Proc.new { "this is the #{type} target host: :host" })
|
181
|
+
]
|
182
|
+
@exp_val_cmds = [
|
183
|
+
"this is the local target db: testdb",
|
184
|
+
"this is the local target host: testhost"
|
185
|
+
]
|
186
|
+
end
|
187
|
+
|
188
|
+
should "be an Array" do
|
189
|
+
assert_kind_of ::Array, Settings::CmdList.new
|
190
|
+
end
|
191
|
+
|
192
|
+
should "return the commands, eval'd and placeholders applied" do
|
193
|
+
val_cmds = Settings::CmdList.new(@cmds).value(@script, @script.target.to_hash)
|
194
|
+
assert_equal @exp_val_cmds, val_cmds
|
195
|
+
end
|
196
|
+
|
197
|
+
end
|
198
|
+
|
199
|
+
|
200
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
module Dumpdb
|
2
|
+
|
3
|
+
class FakeCmdRunner
|
4
|
+
|
5
|
+
def self.cmds
|
6
|
+
@@cmds ||= []
|
7
|
+
@@cmds
|
8
|
+
end
|
9
|
+
|
10
|
+
def self.reset
|
11
|
+
@@cmds = []
|
12
|
+
end
|
13
|
+
|
14
|
+
def initialize(cmd)
|
15
|
+
@cmd = cmd
|
16
|
+
end
|
17
|
+
|
18
|
+
def run!
|
19
|
+
run
|
20
|
+
end
|
21
|
+
|
22
|
+
def run
|
23
|
+
FakeCmdRunner.cmds << @cmd
|
24
|
+
end
|
25
|
+
|
26
|
+
end
|
27
|
+
|
28
|
+
end
|
@@ -0,0 +1,66 @@
|
|
1
|
+
require 'dumpdb'
|
2
|
+
|
3
|
+
class LocalScript
|
4
|
+
include Dumpdb
|
5
|
+
|
6
|
+
databases { 'test/support/database.yaml' }
|
7
|
+
dump_file { "dump.#{type}" }
|
8
|
+
source { db('development', :another => 'value') }
|
9
|
+
target { db('test') }
|
10
|
+
|
11
|
+
def type; "local"; end
|
12
|
+
end
|
13
|
+
|
14
|
+
class RemoteScript
|
15
|
+
include Dumpdb
|
16
|
+
|
17
|
+
ssh { 'user@example.com' }
|
18
|
+
databases { 'test/support/database.yaml' }
|
19
|
+
dump_file { "dump.#{type}" }
|
20
|
+
source { db('development') }
|
21
|
+
target { db('test') }
|
22
|
+
|
23
|
+
def type; "remote"; end
|
24
|
+
end
|
25
|
+
|
26
|
+
class RunnerScript
|
27
|
+
include Dumpdb
|
28
|
+
|
29
|
+
dump_file { 'dump.output' }
|
30
|
+
|
31
|
+
dump { 'a dump cmd' }
|
32
|
+
restore { 'a restore cmd' }
|
33
|
+
|
34
|
+
def initialize
|
35
|
+
@before_cmd_run = 0
|
36
|
+
@after_cmd_run = 0
|
37
|
+
end
|
38
|
+
|
39
|
+
def all_callbacks_called?
|
40
|
+
!!(@before_run && @after_run &&
|
41
|
+
@before_setup && @after_setup &&
|
42
|
+
@before_dump && @after_dump &&
|
43
|
+
@before_copy_dump && @after_copy_dump &&
|
44
|
+
@before_restore && @after_restore &&
|
45
|
+
@before_teardown && @after_teardown &&
|
46
|
+
@before_cmd_run == 7 &&
|
47
|
+
@after_cmd_run == 7
|
48
|
+
)
|
49
|
+
end
|
50
|
+
|
51
|
+
def before_run(*args); @before_run = true; end
|
52
|
+
def after_run(*args); @after_run = true; end
|
53
|
+
def before_setup(*args); @before_setup = true; end
|
54
|
+
def after_setup(*args); @after_setup = true; end
|
55
|
+
def before_dump(*args); @before_dump = true; end
|
56
|
+
def after_dump(*args); @after_dump = true; end
|
57
|
+
def before_copy_dump(*args); @before_copy_dump = true; end
|
58
|
+
def after_copy_dump(*args); @after_copy_dump = true; end
|
59
|
+
def before_restore(*args); @before_restore = true; end
|
60
|
+
def after_restore(*args); @after_restore = true; end
|
61
|
+
def before_teardown(*args); @before_teardown = true; end
|
62
|
+
def after_teardown(*args); @after_teardown = true; end
|
63
|
+
def before_cmd_run(*args); @before_cmd_run += 1; end
|
64
|
+
def after_cmd_run(*args); @after_cmd_run += 1; end
|
65
|
+
|
66
|
+
end
|
metadata
ADDED
@@ -0,0 +1,147 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: dumpdb
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
hash: 3130626483
|
5
|
+
prerelease: 6
|
6
|
+
segments:
|
7
|
+
- 1
|
8
|
+
- 0
|
9
|
+
- 0
|
10
|
+
- rc
|
11
|
+
- 1
|
12
|
+
version: 1.0.0.rc1
|
13
|
+
platform: ruby
|
14
|
+
authors:
|
15
|
+
- Kelly Redding
|
16
|
+
- Collin Redding
|
17
|
+
autorequire:
|
18
|
+
bindir: bin
|
19
|
+
cert_chain: []
|
20
|
+
|
21
|
+
date: 2012-11-21 00:00:00 Z
|
22
|
+
dependencies:
|
23
|
+
- !ruby/object:Gem::Dependency
|
24
|
+
name: assert
|
25
|
+
version_requirements: &id001 !ruby/object:Gem::Requirement
|
26
|
+
none: false
|
27
|
+
requirements:
|
28
|
+
- - ">="
|
29
|
+
- !ruby/object:Gem::Version
|
30
|
+
hash: 3
|
31
|
+
segments:
|
32
|
+
- 0
|
33
|
+
version: "0"
|
34
|
+
type: :development
|
35
|
+
requirement: *id001
|
36
|
+
prerelease: false
|
37
|
+
- !ruby/object:Gem::Dependency
|
38
|
+
name: scmd
|
39
|
+
version_requirements: &id002 !ruby/object:Gem::Requirement
|
40
|
+
none: false
|
41
|
+
requirements:
|
42
|
+
- - ~>
|
43
|
+
- !ruby/object:Gem::Version
|
44
|
+
hash: 3
|
45
|
+
segments:
|
46
|
+
- 2
|
47
|
+
- 0
|
48
|
+
version: "2.0"
|
49
|
+
type: :runtime
|
50
|
+
requirement: *id002
|
51
|
+
prerelease: false
|
52
|
+
- !ruby/object:Gem::Dependency
|
53
|
+
name: ns-options
|
54
|
+
version_requirements: &id003 !ruby/object:Gem::Requirement
|
55
|
+
none: false
|
56
|
+
requirements:
|
57
|
+
- - "="
|
58
|
+
- !ruby/object:Gem::Version
|
59
|
+
hash: 3130626483
|
60
|
+
segments:
|
61
|
+
- 1
|
62
|
+
- 0
|
63
|
+
- 0
|
64
|
+
- rc
|
65
|
+
- 1
|
66
|
+
version: 1.0.0.rc1
|
67
|
+
type: :runtime
|
68
|
+
requirement: *id003
|
69
|
+
prerelease: false
|
70
|
+
description: Dump and restore your databases.
|
71
|
+
email:
|
72
|
+
- kelly@kellyredding.com
|
73
|
+
- collin.redding@me.com
|
74
|
+
executables: []
|
75
|
+
|
76
|
+
extensions: []
|
77
|
+
|
78
|
+
extra_rdoc_files: []
|
79
|
+
|
80
|
+
files:
|
81
|
+
- .gitignore
|
82
|
+
- Gemfile
|
83
|
+
- LICENSE
|
84
|
+
- README.md
|
85
|
+
- Rakefile
|
86
|
+
- dumpdb.gemspec
|
87
|
+
- lib/dumpdb.rb
|
88
|
+
- lib/dumpdb/db.rb
|
89
|
+
- lib/dumpdb/runner.rb
|
90
|
+
- lib/dumpdb/settings.rb
|
91
|
+
- lib/dumpdb/version.rb
|
92
|
+
- test/db_tests.rb
|
93
|
+
- test/helper.rb
|
94
|
+
- test/irb.rb
|
95
|
+
- test/runner_tests.rb
|
96
|
+
- test/script_tests.rb
|
97
|
+
- test/settings_tests.rb
|
98
|
+
- test/support/database.yaml
|
99
|
+
- test/support/fake_cmd_runner.rb
|
100
|
+
- test/support/test.yaml
|
101
|
+
- test/support/test_scripts.rb
|
102
|
+
homepage: http://github.com/redding/dumpdb
|
103
|
+
licenses: []
|
104
|
+
|
105
|
+
post_install_message:
|
106
|
+
rdoc_options: []
|
107
|
+
|
108
|
+
require_paths:
|
109
|
+
- lib
|
110
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
111
|
+
none: false
|
112
|
+
requirements:
|
113
|
+
- - ">="
|
114
|
+
- !ruby/object:Gem::Version
|
115
|
+
hash: 3
|
116
|
+
segments:
|
117
|
+
- 0
|
118
|
+
version: "0"
|
119
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
120
|
+
none: false
|
121
|
+
requirements:
|
122
|
+
- - ">"
|
123
|
+
- !ruby/object:Gem::Version
|
124
|
+
hash: 25
|
125
|
+
segments:
|
126
|
+
- 1
|
127
|
+
- 3
|
128
|
+
- 1
|
129
|
+
version: 1.3.1
|
130
|
+
requirements: []
|
131
|
+
|
132
|
+
rubyforge_project:
|
133
|
+
rubygems_version: 1.8.24
|
134
|
+
signing_key:
|
135
|
+
specification_version: 3
|
136
|
+
summary: Dump and restore your databases.
|
137
|
+
test_files:
|
138
|
+
- test/db_tests.rb
|
139
|
+
- test/helper.rb
|
140
|
+
- test/irb.rb
|
141
|
+
- test/runner_tests.rb
|
142
|
+
- test/script_tests.rb
|
143
|
+
- test/settings_tests.rb
|
144
|
+
- test/support/database.yaml
|
145
|
+
- test/support/fake_cmd_runner.rb
|
146
|
+
- test/support/test.yaml
|
147
|
+
- test/support/test_scripts.rb
|