arcopy 0.0.1
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.
- checksums.yaml +7 -0
- data/COPYING +18 -0
- data/HACKING +61 -0
- data/README.md +285 -0
- data/Rakefile +16 -0
- data/bin/replicate +100 -0
- data/lib/replicate.rb +24 -0
- data/lib/replicate/active_record.rb +347 -0
- data/lib/replicate/dumper.rb +142 -0
- data/lib/replicate/emitter.rb +54 -0
- data/lib/replicate/loader.rb +157 -0
- data/lib/replicate/object.rb +57 -0
- data/lib/replicate/status.rb +54 -0
- data/test/active_record_test.rb +589 -0
- data/test/dumper_test.rb +108 -0
- data/test/dumpscript.rb +1 -0
- data/test/linked_dumpscript.rb +1 -0
- data/test/loader_test.rb +93 -0
- data/test/replicate_test.rb +10 -0
- metadata +135 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: ba25896eb10e1027cf4021ea88ba0fb5517c630907d442bfc5b27ed861f41677
|
4
|
+
data.tar.gz: d035b464d641f563962a1b3040e9fe894c848a0625e458f0e6385c92ffa78a4d
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 7f784501bd721c2be2ccfe16c740f84da92a43edd2b0a02ffe356de940e8db4a0906d701dafc643e1ee5e9d571e10916f46e3f5e2bedb595df4e63e44acfa695
|
7
|
+
data.tar.gz: d856708d946dacd3366015d7d4d11bd3e7aa2e87562b97367b2fd67627e5ccb551b17c719e4b3a526cc8f2f646d0d9c9f6699c547d31eaec2f94438c4f778e25
|
data/COPYING
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
Copyright (c) 2011 Ryan Tomayko <http://tomayko.com/about>
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
4
|
+
of this software and associated documentation files (the "Software"), to
|
5
|
+
deal in the Software without restriction, including without limitation the
|
6
|
+
rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
7
|
+
sell copies of the Software, and to permit persons to whom the Software is
|
8
|
+
furnished to do so, subject to the following conditions:
|
9
|
+
|
10
|
+
The above copyright notice and this permission notice shall be included in
|
11
|
+
all copies or substantial portions of the Software.
|
12
|
+
|
13
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
14
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
15
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
16
|
+
THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
17
|
+
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
18
|
+
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/HACKING
ADDED
@@ -0,0 +1,61 @@
|
|
1
|
+
Grab a local clone of rtomayko/replicate:
|
2
|
+
|
3
|
+
git clone git://github.com/rtomayko/replicate.git
|
4
|
+
cd replicate
|
5
|
+
|
6
|
+
The default rake task installs the latest supported activerecord
|
7
|
+
version to a project local GEM_HOME=./vendor and runs the unit
|
8
|
+
tests:
|
9
|
+
|
10
|
+
$ rake
|
11
|
+
installing activerecord-3.1.0 to ./vendor/1.8
|
12
|
+
installing sqlite3 to ./vendor/1.8
|
13
|
+
Using activerecord 3.1.0
|
14
|
+
Loaded suite ...
|
15
|
+
Started
|
16
|
+
....................
|
17
|
+
Finished in 0.150186 seconds.
|
18
|
+
|
19
|
+
20 tests, 106 assertions, 0 failures, 0 errors
|
20
|
+
|
21
|
+
Use `rake test:all' to run tests under all activerecord versions:
|
22
|
+
|
23
|
+
$ rake test:all
|
24
|
+
installing activerecord ~> 2.2.3 to ./vendor
|
25
|
+
installing activerecord ~> 2.3.14 to ./vendor
|
26
|
+
installing activerecord ~> 3.0.10 to ./vendor
|
27
|
+
installing activerecord ~> 3.1.0 to ./vendor
|
28
|
+
==> testing activerecord ~> 2.2.3
|
29
|
+
Started
|
30
|
+
....................
|
31
|
+
Finished in 0.119517 seconds.
|
32
|
+
|
33
|
+
20 tests, 106 assertions, 0 failures, 0 errors
|
34
|
+
==> testing activerecord ~> 2.3.14
|
35
|
+
Started
|
36
|
+
....................
|
37
|
+
Finished in 0.119517 seconds.
|
38
|
+
|
39
|
+
20 tests, 106 assertions, 0 failures, 0 errors
|
40
|
+
<snip>
|
41
|
+
|
42
|
+
rake test:all should always be passing under latest stable MRI
|
43
|
+
1.8.7 and MRI 1.9.x.
|
44
|
+
|
45
|
+
Running individual test files directly requires setting the
|
46
|
+
GEM_HOME environment variable and ensuring ./lib is on the load
|
47
|
+
path:
|
48
|
+
|
49
|
+
export GEM_HOME=vendor/1.9 # or 1.8.7
|
50
|
+
ruby -Ilib test/active_record_test.rb
|
51
|
+
|
52
|
+
You can also control which activerecord version is used in the
|
53
|
+
test with the AR_VERSION environment variable:
|
54
|
+
|
55
|
+
rake setup:all
|
56
|
+
export GEM_HOME=vendor/1.8.7
|
57
|
+
AR_VERSION=3.1.0 ruby -rubygems -Ilib test/active_record_test.rb
|
58
|
+
|
59
|
+
If you have something worth sharing, please send a pull request:
|
60
|
+
|
61
|
+
https://github.com/rtomayko/replicate
|
data/README.md
ADDED
@@ -0,0 +1,285 @@
|
|
1
|
+
Dump and load relational objects between Ruby environments.
|
2
|
+
===========================================================
|
3
|
+
|
4
|
+
*This repository is archived and no longer actively maintained by @rtomayko as of 2017-11-08. Issues and PRs documenting current issues have been intentionally left open for informational purposes.*
|
5
|
+
|
6
|
+
The project started at GitHub to simplify the process of getting real production
|
7
|
+
data into development and staging environments. We use it to replicate entire
|
8
|
+
repository data (including associated issue, pull request, commit comment, etc.
|
9
|
+
records) from production to our development environments with a single command.
|
10
|
+
It's excessively useful for troubleshooting issues, support requests, and
|
11
|
+
exception reports as well as for establishing real data for evaluating design
|
12
|
+
concepts.
|
13
|
+
|
14
|
+
Synopsis
|
15
|
+
--------
|
16
|
+
|
17
|
+
### Installing
|
18
|
+
|
19
|
+
$ gem install replicate
|
20
|
+
|
21
|
+
### Dumping objects
|
22
|
+
|
23
|
+
Evaluate a Ruby expression, dumping all resulting objects to standard output:
|
24
|
+
|
25
|
+
$ replicate -r ./config/environment -d "User.find(1)" > user.dump
|
26
|
+
==> dumped 4 total objects:
|
27
|
+
Profile 1
|
28
|
+
User 1
|
29
|
+
UserEmail 2
|
30
|
+
|
31
|
+
The `-r ./config/environment` option is used to require environment setup and
|
32
|
+
model instantiation code needed by the ruby expression.
|
33
|
+
|
34
|
+
### Dumping many objects with a dump script
|
35
|
+
|
36
|
+
Dump scripts are normal ruby source files evaluated in the context of the
|
37
|
+
dumper. The `dump(object)` method is used to put objects into the dump stream.
|
38
|
+
|
39
|
+
```ruby
|
40
|
+
# config/replicate/dump-stuff.rb
|
41
|
+
require 'config/environment'
|
42
|
+
|
43
|
+
%w[rtomayko/tilt rtomayko/bcat].each do |repo_name|
|
44
|
+
repo = Repository.find_by_name_with_owner(repo_name)
|
45
|
+
dump repo
|
46
|
+
dump repo.commit_comments
|
47
|
+
dump repo.issues
|
48
|
+
end
|
49
|
+
```
|
50
|
+
|
51
|
+
Run the dump script:
|
52
|
+
|
53
|
+
$ replicate -d config/replicate/dump-stuff.rb > repos.dump
|
54
|
+
==> dumped 1479 total objects:
|
55
|
+
AR::Habtm 101
|
56
|
+
CommitComment 95
|
57
|
+
Issue 101
|
58
|
+
IssueComment 427
|
59
|
+
IssueEvent 308
|
60
|
+
Label 5
|
61
|
+
Language 19
|
62
|
+
LanguageName 1
|
63
|
+
Milestone 3
|
64
|
+
Organization 4
|
65
|
+
Profile 82
|
66
|
+
PullRequest 44
|
67
|
+
PullRequestReviewComment 8
|
68
|
+
Repository 20
|
69
|
+
Team 4
|
70
|
+
TeamMember 6
|
71
|
+
User 89
|
72
|
+
UserEmail 162
|
73
|
+
|
74
|
+
### Loading many objects:
|
75
|
+
|
76
|
+
$ replicate -r ./config/environment -l < repos.dump
|
77
|
+
==> loaded 1479 total objects:
|
78
|
+
AR::Habtm 101
|
79
|
+
CommitComment 95
|
80
|
+
Issue 101
|
81
|
+
IssueComment 427
|
82
|
+
IssueEvent 308
|
83
|
+
Label 5
|
84
|
+
Language 19
|
85
|
+
LanguageName 1
|
86
|
+
Milestone 3
|
87
|
+
Organization 4
|
88
|
+
Profile 82
|
89
|
+
PullRequest 44
|
90
|
+
PullRequestReviewComment 8
|
91
|
+
Repository 20
|
92
|
+
Team 4
|
93
|
+
TeamMember 6
|
94
|
+
User 89
|
95
|
+
UserEmail 162
|
96
|
+
|
97
|
+
### Dumping and loading over ssh
|
98
|
+
|
99
|
+
$ remote_command="replicate -r /app/config/environment -d 'User.find(1234)'"
|
100
|
+
$ ssh example.org "$remote_command" |replicate -r ./config/environment -l
|
101
|
+
|
102
|
+
ActiveRecord
|
103
|
+
------------
|
104
|
+
|
105
|
+
Basic support for dumping and loading ActiveRecord objects is included. The
|
106
|
+
tests pass under ActiveRecord versions 2.2.3, 2.3.5, 2.3.14, 3.0.10, 3.1.0, and 3.2.0 under
|
107
|
+
MRI 1.8.7 as well as under MRI 1.9.2.
|
108
|
+
|
109
|
+
To use customization macros in your models, require the replicate library after
|
110
|
+
ActiveRecord (in e.g., `config/initializers/libraries.rb`):
|
111
|
+
|
112
|
+
```ruby
|
113
|
+
require 'active_record'
|
114
|
+
require 'replicate'
|
115
|
+
```
|
116
|
+
|
117
|
+
ActiveRecord support works sensibly without customization so this isn't strictly
|
118
|
+
necessary to use the `replicate` command. The following sections document the
|
119
|
+
available customization macros.
|
120
|
+
|
121
|
+
### Association Dumping
|
122
|
+
|
123
|
+
The baked in support adds some more or less sensible default behavior for all
|
124
|
+
subclasses of `ActiveRecord::Base` such that dumping an object will bring in
|
125
|
+
objects related via `belongs_to` and `has_one` associations.
|
126
|
+
|
127
|
+
Unlike 1:1 associations, `has_many` and `has_and_belongs_to_many` associations
|
128
|
+
are not automatically included. Doing so would quickly lead to the entire
|
129
|
+
database being sucked in. It can be useful to mark specific associations for
|
130
|
+
automatic inclusion using the `replicate_associations` macro. For instance,
|
131
|
+
to always include `EmailAddress` records belonging to a `User`:
|
132
|
+
|
133
|
+
```ruby
|
134
|
+
class User < ActiveRecord::Base
|
135
|
+
belongs_to :profile
|
136
|
+
has_many :email_addresses
|
137
|
+
|
138
|
+
replicate_associations :email_addresses
|
139
|
+
end
|
140
|
+
```
|
141
|
+
|
142
|
+
You may also do this by passing an option in your dump script:
|
143
|
+
|
144
|
+
```ruby
|
145
|
+
dump User.all, :associations => [:email_addresses]
|
146
|
+
```
|
147
|
+
|
148
|
+
### Natural Keys
|
149
|
+
|
150
|
+
By default, the loader attempts to create a new record with a new primary key id
|
151
|
+
for all objects. This can lead to unique constraint errors when a record already
|
152
|
+
exists with matching attributes. To update existing records instead of
|
153
|
+
creating new ones, define a natural key for the model using the `replicate_natural_key`
|
154
|
+
macro:
|
155
|
+
|
156
|
+
```ruby
|
157
|
+
class User < ActiveRecord::Base
|
158
|
+
belongs_to :profile
|
159
|
+
has_many :email_addresses
|
160
|
+
|
161
|
+
replicate_natural_key :login
|
162
|
+
replicate_associations :email_addresses
|
163
|
+
end
|
164
|
+
|
165
|
+
class EmailAddress < ActiveRecord::Base
|
166
|
+
belongs_to :user
|
167
|
+
replicate_natural_key :user_id, :email
|
168
|
+
end
|
169
|
+
```
|
170
|
+
|
171
|
+
Multiple attribute names may be specified to define a compound key. Foreign key
|
172
|
+
column attributes (`user_id`) are often included in natural keys.
|
173
|
+
|
174
|
+
### Omission of attributes and associations
|
175
|
+
|
176
|
+
You might want to exclude some attributes or associations from being dumped. For
|
177
|
+
this, use the replicate_omit_attributes macro:
|
178
|
+
|
179
|
+
```ruby
|
180
|
+
class User < ActiveRecord::Base
|
181
|
+
has_one :profile
|
182
|
+
|
183
|
+
replicate_omit_attributes :created_at, :profile
|
184
|
+
end
|
185
|
+
```
|
186
|
+
|
187
|
+
You can omit belongs_to associations by omitting the foreign key column.
|
188
|
+
|
189
|
+
You may also do this by passing an option in your dump script:
|
190
|
+
|
191
|
+
```ruby
|
192
|
+
dump User.all, :omit => [:profile]
|
193
|
+
```
|
194
|
+
|
195
|
+
### Validations and Callbacks
|
196
|
+
|
197
|
+
__IMPORTANT:__ All ActiveRecord validations and callbacks are disabled on the
|
198
|
+
loading side. While replicate piggybacks on AR for relationship information and
|
199
|
+
uses `ActiveRecord::Base#save` to write objects to the database, it's designed
|
200
|
+
to act as a simple dump / load tool.
|
201
|
+
|
202
|
+
It's sometimes useful to run certain types of callbacks on replicate. For
|
203
|
+
instance, you might want to create files on disk or load information into a
|
204
|
+
separate data store any time an object enters the database. The best way to go
|
205
|
+
about this currently is to override the model's `load_replicant` class method:
|
206
|
+
|
207
|
+
```ruby
|
208
|
+
class User < ActiveRecord::Base
|
209
|
+
def self.load_replicant(type, id, attrs)
|
210
|
+
id, object = super
|
211
|
+
object.register_in_redis
|
212
|
+
object.some_other_callback
|
213
|
+
[id, object]
|
214
|
+
end
|
215
|
+
end
|
216
|
+
```
|
217
|
+
|
218
|
+
This interface will be improved in future versions.
|
219
|
+
|
220
|
+
Custom Objects
|
221
|
+
--------------
|
222
|
+
|
223
|
+
Other object types may be included in the dump stream so long as they implement
|
224
|
+
the `dump_replicant` and `load_replicant` methods.
|
225
|
+
|
226
|
+
### dump_replicant
|
227
|
+
|
228
|
+
The dump side calls `#dump_replicant(dumper, opts={})` on each object. The method must
|
229
|
+
call `dumper.write()` with the class name, id, and hash of primitively typed
|
230
|
+
attributes for the object:
|
231
|
+
|
232
|
+
```ruby
|
233
|
+
class User
|
234
|
+
attr_reader :id
|
235
|
+
attr_accessor :name, :email
|
236
|
+
|
237
|
+
def dump_replicant(dumper, opts={})
|
238
|
+
attributes = { 'name' => name, 'email' => email }
|
239
|
+
dumper.write self.class, id, attributes, self
|
240
|
+
end
|
241
|
+
end
|
242
|
+
```
|
243
|
+
|
244
|
+
### load_replicant
|
245
|
+
|
246
|
+
The load side calls `::load_replicant(type, id, attributes)` on the class to
|
247
|
+
load each object into the current environment. The method must return an
|
248
|
+
`[id, object]` tuple:
|
249
|
+
|
250
|
+
```ruby
|
251
|
+
class User
|
252
|
+
def self.load_replicant(type, id, attributes)
|
253
|
+
user = User.new
|
254
|
+
user.name = attributes['name']
|
255
|
+
user.email = attributes['email']
|
256
|
+
user.save!
|
257
|
+
[user.id, user]
|
258
|
+
end
|
259
|
+
end
|
260
|
+
```
|
261
|
+
|
262
|
+
How it works
|
263
|
+
------------
|
264
|
+
|
265
|
+
The dump format is designed for streaming relational data. Each object is
|
266
|
+
encoded as a `[type, id, attributes]` tuple and marshalled directly onto the
|
267
|
+
stream. The `type` (class name string) and `id` must form a distinct key when
|
268
|
+
combined, `attributes` must consist of only string keys and simply typed values.
|
269
|
+
|
270
|
+
Relationships between objects in the stream are managed as follows:
|
271
|
+
|
272
|
+
- An object's attributes may encode references to objects that precede it
|
273
|
+
in the stream using a simple tuple format: `[:id, 'User', 1234]`.
|
274
|
+
|
275
|
+
- The dump side ensures that objects are written to the dump stream in
|
276
|
+
"reference order" such that when an object A includes a reference attribute
|
277
|
+
to an object B, B is guaranteed to arrive before A.
|
278
|
+
|
279
|
+
- The load side maintains a mapping of ids from the dumping system to the newly
|
280
|
+
replicated objects on the loading system. When the loader encounters a
|
281
|
+
reference value `[:id, 'User', 1234]` in an object's attributes, it converts it
|
282
|
+
to the load side id value.
|
283
|
+
|
284
|
+
Dumping and loading happens in a streaming fashion. There is no limit on the
|
285
|
+
number of objects included in the stream.
|
data/Rakefile
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
require 'rake/clean'
|
2
|
+
require 'rake/testtask'
|
3
|
+
|
4
|
+
task :default => :test
|
5
|
+
|
6
|
+
desc "Run tests"
|
7
|
+
Rake::TestTask.new do |t|
|
8
|
+
t.test_files = FileList['test/*_test.rb']
|
9
|
+
end
|
10
|
+
|
11
|
+
CLEAN.include 'test/db'
|
12
|
+
|
13
|
+
desc "Build gem"
|
14
|
+
task :build do
|
15
|
+
sh "gem build replicate.gemspec"
|
16
|
+
end
|
data/bin/replicate
ADDED
@@ -0,0 +1,100 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
#/ Usage: replicate --dump dumpscript.rb > objects.dump
|
3
|
+
#/ replicate [-r <lib>] --dump "<ruby>" [-- <argv>...] > objects.dump
|
4
|
+
#/ replicate [-r <lib>] --load < objects.dump
|
5
|
+
#/ Dump and load objects between environments.
|
6
|
+
#
|
7
|
+
#/ The --dump form writes to stdout the objects dumped by the script or
|
8
|
+
#/ ruby expression(s) given. Dump scripts are normal Ruby source files but
|
9
|
+
#/ must call dump(object) on one or more objects. When a Ruby expression is
|
10
|
+
#/ given, all resulting objects are dumped automatically.
|
11
|
+
#/
|
12
|
+
#/ Dump scripts have access to any additional <argv> provided via the normal
|
13
|
+
#/ system ARGV array. This can be used to pass arguments to dump scripts.
|
14
|
+
#/
|
15
|
+
#/ The --load form reads dump data from stdin and creates objects under the
|
16
|
+
#/ current environment.
|
17
|
+
#/
|
18
|
+
#/ Mode selection:
|
19
|
+
#/ -d, --dump Dump the repository and all related objects to stdout.
|
20
|
+
#/ -l, --load Load dump file data from stdin.
|
21
|
+
#/
|
22
|
+
#/ Options:
|
23
|
+
#/ -r, --require Require the library. Often used with 'config/environment'.
|
24
|
+
#/ -i, --keep-id Use replicated ids when loading dump file.
|
25
|
+
#/ -f, --force Allow loading in production environments.
|
26
|
+
#/ -v, --verbose Write more status output.
|
27
|
+
#/ -q, --quiet Write less status output.
|
28
|
+
$stderr.sync = true
|
29
|
+
$stdout = $stderr
|
30
|
+
|
31
|
+
require 'optparse'
|
32
|
+
|
33
|
+
# default options
|
34
|
+
mode = nil
|
35
|
+
verbose = false
|
36
|
+
quiet = false
|
37
|
+
keep_id = false
|
38
|
+
out = STDOUT
|
39
|
+
force = false
|
40
|
+
|
41
|
+
# parse arguments
|
42
|
+
file = __FILE__
|
43
|
+
usage = lambda { exec "grep ^#/<'#{file}'|cut -c4-" }
|
44
|
+
original_argv = ARGV.dup
|
45
|
+
ARGV.options do |opts|
|
46
|
+
opts.on("-d", "--dump") { mode = :dump }
|
47
|
+
opts.on("-l", "--load") { mode = :load }
|
48
|
+
opts.on("-r", "--require=f") { |file| require file }
|
49
|
+
opts.on("-v", "--verbose") { verbose = true }
|
50
|
+
opts.on("-q", "--quiet") { quiet = true }
|
51
|
+
opts.on("-i", "--keep-id") { keep_id = true }
|
52
|
+
opts.on("--force") { force = true }
|
53
|
+
opts.on_tail("-h", "--help", &usage)
|
54
|
+
opts.parse!
|
55
|
+
end
|
56
|
+
|
57
|
+
# load replicate lib and setup AR
|
58
|
+
require 'replicate'
|
59
|
+
if defined?(ActiveRecord::Base)
|
60
|
+
require 'replicate/active_record'
|
61
|
+
ActiveRecord::Base.replicate_id = keep_id
|
62
|
+
ActiveRecord::Base.connection.enable_query_cache!
|
63
|
+
end
|
64
|
+
|
65
|
+
# dump mode means we're reading records from the database here and writing to
|
66
|
+
# stdout. the database should not be modified at all by this operation.
|
67
|
+
if mode == :dump
|
68
|
+
script = ARGV.shift
|
69
|
+
usage.call if script.empty?
|
70
|
+
Replicate::Dumper.new do |dumper|
|
71
|
+
dumper.marshal_to out
|
72
|
+
dumper.log_to $stderr, verbose, quiet
|
73
|
+
if script == '-'
|
74
|
+
code = $stdin.read
|
75
|
+
objects = dumper.instance_eval(code, '<stdin>', 0)
|
76
|
+
elsif File.exist?(script)
|
77
|
+
dumper.load_script script
|
78
|
+
else
|
79
|
+
objects = dumper.instance_eval(script, '<argv>', 0)
|
80
|
+
dumper.dump objects
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
# load mode means we're reading objects from stdin and creating them under
|
85
|
+
# the current environment.
|
86
|
+
elsif mode == :load
|
87
|
+
if Replicate.production_environment? && !force
|
88
|
+
abort "error: refusing to load in production environment\n" +
|
89
|
+
" manual override: #{File.basename($0)} --force #{original_argv.join(' ')}"
|
90
|
+
else
|
91
|
+
Replicate::Loader.new do |loader|
|
92
|
+
loader.log_to $stderr, verbose, quiet
|
93
|
+
loader.read $stdin
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
# mode not set means no -l or -d arg was given. show usage and bail.
|
98
|
+
else
|
99
|
+
usage.call
|
100
|
+
end
|