bibliotech 0.2.13 → 0.3.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/default_configuration/config.yaml +3 -0
- data/lib/bibliotech/application.rb +25 -2
- data/lib/bibliotech/backups/file_record.rb +7 -1
- data/lib/bibliotech/backups/prune_list.rb +3 -1
- data/lib/bibliotech/backups/pruner.rb +17 -9
- data/lib/bibliotech/backups/scheduler.rb +4 -3
- data/lib/bibliotech/command_generator.rb +15 -3
- data/lib/bibliotech/config.rb +35 -5
- data/lib/bibliotech/logger.rb +36 -0
- data/spec/bibliotech/backup_pruner_spec.rb +121 -6
- data/spec/bibliotech/backup_scheduler_spec.rb +2 -2
- data/spec/bibliotech/config_spec.rb +2 -4
- data/spec/spec_helper.rb +4 -0
- metadata +4 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 07e130f15c7d64d6bd751f7663a913adb30a5551
|
4
|
+
data.tar.gz: efc5d69b6b40c211c0959020bfaf7ab46044ec56
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 95ac9c114a022bbbda10710e62a4f9191aa242f7f9c4b68aa8fd9576424c65309e168bbc5b0ed0e5727477af76be81017cd71ceeca87e2c25cd1488d57e0a2b3
|
7
|
+
data.tar.gz: 88626b4a157c11e5d4294bfd3aa8a7b730db4f685c5e755a83f87935e27cd42a37b7fc00a44a95be0342489689e68278411b73ccd68d24d17c46d21d0f951a83
|
@@ -2,9 +2,12 @@ require 'bibliotech'
|
|
2
2
|
require 'caliph'
|
3
3
|
require 'valise'
|
4
4
|
require 'bibliotech/backups/pruner'
|
5
|
+
require 'bibliotech/logger'
|
5
6
|
|
6
7
|
module BiblioTech
|
7
8
|
class Application
|
9
|
+
include Logging
|
10
|
+
|
8
11
|
attr_accessor :config_path, :config_hash
|
9
12
|
attr_writer :shell
|
10
13
|
|
@@ -30,7 +33,19 @@ module BiblioTech
|
|
30
33
|
end
|
31
34
|
|
32
35
|
def config
|
33
|
-
@memos[:config] ||=
|
36
|
+
@memos[:config] ||=
|
37
|
+
begin
|
38
|
+
Config.new(valise).tap do |config|
|
39
|
+
setup_logger(config)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
def setup_logger(config)
|
45
|
+
logger = Logger.new(config.log_target)
|
46
|
+
logger.level = config.log_level
|
47
|
+
BiblioTech::Logging.logger = logger
|
48
|
+
log.info("Started logging")
|
34
49
|
end
|
35
50
|
|
36
51
|
def commands
|
@@ -59,6 +74,7 @@ module BiblioTech
|
|
59
74
|
|
60
75
|
def create_backup(options)
|
61
76
|
time = Time.now.utc
|
77
|
+
log.warn{ "Creating a backup at #{time}" }
|
62
78
|
pruner = pruner(options)
|
63
79
|
return unless pruner.backup_needed?(time)
|
64
80
|
options["backups"] ||= options[:backups] || {}
|
@@ -68,25 +84,32 @@ module BiblioTech
|
|
68
84
|
|
69
85
|
#pull a dump from a remote
|
70
86
|
def get(remote, options)
|
87
|
+
log.warn{ "Getting a dump from #{remote}" }
|
71
88
|
@shell.run(commands.fetch(remote, options))
|
72
89
|
end
|
73
90
|
|
74
91
|
#push a dump to a remote
|
75
92
|
def send(remote, options)
|
93
|
+
log.warn{ "Sending a dump to #{remote}" }
|
76
94
|
@shell.run(commands.push(remote, options))
|
77
95
|
end
|
78
96
|
|
79
97
|
#clean up the DB dumps
|
80
98
|
def prune(options=nil)
|
99
|
+
log.warn{ "Pruning DB records" }
|
81
100
|
pruner(options || {}).go
|
82
101
|
end
|
83
102
|
|
84
103
|
#return the latest dump of the DB
|
85
104
|
def latest(options = nil)
|
86
|
-
|
105
|
+
log.info{ "Getting most recent DB dump" }
|
106
|
+
pruner(options || {}).most_recent.path.tap do |latest|
|
107
|
+
log.info{ " #{latest}" }
|
108
|
+
end
|
87
109
|
end
|
88
110
|
|
89
111
|
def remote_cli(remote, command, *options)
|
112
|
+
log.warn{ "Running #{command} on #{remote}" }
|
90
113
|
@shell.run(commands.remote_cli(remote, command, *options))
|
91
114
|
end
|
92
115
|
end
|
@@ -1,16 +1,22 @@
|
|
1
1
|
module BiblioTech
|
2
2
|
module Backups
|
3
3
|
class FileRecord
|
4
|
-
attr_accessor :path, :timestamp, :keep
|
4
|
+
attr_accessor :path, :timestamp, :keep, :scheduled_by
|
5
5
|
|
6
6
|
def initialize(path, timestamp)
|
7
7
|
@path, @timestamp = path, timestamp
|
8
8
|
@keep = false
|
9
|
+
@scheduled_by = []
|
9
10
|
end
|
10
11
|
|
11
12
|
def keep?
|
12
13
|
!!@keep
|
13
14
|
end
|
15
|
+
|
16
|
+
def in_schedule(name)
|
17
|
+
@scheduled_by << name
|
18
|
+
@keep = true
|
19
|
+
end
|
14
20
|
end
|
15
21
|
end
|
16
22
|
end
|
@@ -1,10 +1,11 @@
|
|
1
1
|
require 'bibliotech/backups/prune_list'
|
2
2
|
require 'bibliotech/backups/file_record'
|
3
|
-
require 'bibliotech/
|
3
|
+
require 'bibliotech/logger'
|
4
4
|
|
5
5
|
module BiblioTech
|
6
6
|
module Backups
|
7
7
|
class Pruner
|
8
|
+
include Logging
|
8
9
|
def initialize(config)
|
9
10
|
@config = config
|
10
11
|
end
|
@@ -19,18 +20,17 @@ module BiblioTech
|
|
19
20
|
end
|
20
21
|
|
21
22
|
def schedules
|
22
|
-
@schedules ||=
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
end
|
23
|
+
@schedules ||= config.prune_schedules
|
24
|
+
end
|
25
|
+
|
26
|
+
def frequency
|
27
|
+
@frequency ||= config.backup_frequency
|
28
28
|
end
|
29
29
|
|
30
30
|
def backup_needed?(time)
|
31
31
|
most_recent = most_recent()
|
32
32
|
return true if most_recent.nil?
|
33
|
-
(time - most_recent.timestamp) > (
|
33
|
+
(time - most_recent.timestamp) > (frequency * 60)
|
34
34
|
end
|
35
35
|
|
36
36
|
def list
|
@@ -50,11 +50,19 @@ module BiblioTech
|
|
50
50
|
end
|
51
51
|
|
52
52
|
def filename_for(time)
|
53
|
-
PruneList.filename_for(
|
53
|
+
PruneList.filename_for(name, time)
|
54
54
|
end
|
55
55
|
|
56
56
|
def pruneable
|
57
57
|
mark_list
|
58
|
+
if list.empty?
|
59
|
+
log.warn{ "No backup files in #{path} / #{name} !" }
|
60
|
+
end
|
61
|
+
list.each do |record|
|
62
|
+
log.info{
|
63
|
+
"#{record.path} #{record.timestamp} #{record.keep ? "kept: #{record.scheduled_by.inspect}" : "discarding"}"
|
64
|
+
}
|
65
|
+
end
|
58
66
|
list.select do |record|
|
59
67
|
!record.keep?
|
60
68
|
end
|
@@ -3,9 +3,10 @@ require 'bibliotech/backups/file_record'
|
|
3
3
|
module BiblioTech
|
4
4
|
module Backups
|
5
5
|
class Scheduler
|
6
|
-
attr_accessor :frequency, :limit
|
6
|
+
attr_accessor :frequency, :limit, :name
|
7
7
|
|
8
|
-
def initialize(frequency, limit)
|
8
|
+
def initialize(name, frequency, limit)
|
9
|
+
@name = name
|
9
10
|
@frequency, @limit = frequency, limit
|
10
11
|
@limit = nil if limit == "all"
|
11
12
|
end
|
@@ -51,7 +52,7 @@ module BiblioTech
|
|
51
52
|
closest = file_list.first
|
52
53
|
|
53
54
|
if (time - closest.timestamp) < freq_seconds
|
54
|
-
closest.
|
55
|
+
closest.in_schedule(name)
|
55
56
|
end
|
56
57
|
time -= freq_seconds
|
57
58
|
end
|
@@ -3,11 +3,13 @@ require 'caliph'
|
|
3
3
|
require 'bibliotech/builders/gzip'
|
4
4
|
require 'bibliotech/builders/postgres'
|
5
5
|
require 'bibliotech/builders/mysql'
|
6
|
+
require 'bibliotech/logger'
|
6
7
|
|
7
8
|
module BiblioTech
|
8
9
|
class CommandGenerator
|
9
10
|
|
10
11
|
include Caliph::CommandLineDSL
|
12
|
+
include Logging
|
11
13
|
|
12
14
|
attr_accessor :config
|
13
15
|
|
@@ -19,14 +21,18 @@ module BiblioTech
|
|
19
21
|
options = config.merge(options || {})
|
20
22
|
command = cmd
|
21
23
|
command = Builders::Export.for(options).go(command)
|
22
|
-
Builders::FileOutput.for(options).go(command)
|
24
|
+
Builders::FileOutput.for(options).go(command).tap do |cmd|
|
25
|
+
log.info{ cmd.command }
|
26
|
+
end
|
23
27
|
end
|
24
28
|
|
25
29
|
def import(options = nil)
|
26
30
|
options = config.merge(options || {})
|
27
31
|
command = cmd()
|
28
32
|
command = Builders::Import.for(options).go(command)
|
29
|
-
Builders::FileInput.for(options).go(command)
|
33
|
+
Builders::FileInput.for(options).go(command).tap do |cmd|
|
34
|
+
log.info{ cmd.command }
|
35
|
+
end
|
30
36
|
end
|
31
37
|
|
32
38
|
def fetch(remote, filename, options = nil)
|
@@ -39,6 +45,8 @@ module BiblioTech
|
|
39
45
|
options.optionally{ cmd.options << "-i #{options.id_file(remote)}" }
|
40
46
|
cmd.options << options.remote_file(remote, filename)
|
41
47
|
cmd.options << local_path
|
48
|
+
end.tap do |cmd|
|
49
|
+
log.info{ cmd.command }
|
42
50
|
end
|
43
51
|
end
|
44
52
|
|
@@ -47,6 +55,8 @@ module BiblioTech
|
|
47
55
|
cmd("scp") do |cmd|
|
48
56
|
cmd.options << options.local_file(filename)
|
49
57
|
cmd.options << options.remote_file(remote, filename)
|
58
|
+
end.tap do |cmd|
|
59
|
+
log.info{ cmd.command }
|
50
60
|
end
|
51
61
|
end
|
52
62
|
|
@@ -74,7 +84,9 @@ module BiblioTech
|
|
74
84
|
cmd.options << "-o #{opt}"
|
75
85
|
end
|
76
86
|
end
|
77
|
-
end - escaped_command(command_on_remote)
|
87
|
+
end - escaped_command(command_on_remote).tap do |cmd|
|
88
|
+
log.info{ cmd.command }
|
89
|
+
end
|
78
90
|
end
|
79
91
|
|
80
92
|
def wipe()
|
data/lib/bibliotech/config.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
require 'bibliotech/backups/scheduler'
|
2
|
+
|
1
3
|
module BiblioTech
|
2
4
|
class Config
|
3
5
|
class MissingConfig < KeyError; end
|
@@ -12,6 +14,8 @@ module BiblioTech
|
|
12
14
|
:rsa_files => [ "rsa_files" ] ,
|
13
15
|
:ssh_options => [ "ssh_options" ] ,
|
14
16
|
:fetch_dir => [ "fetched_dir" ] ,
|
17
|
+
:log_target => [ "log" , "target" ],
|
18
|
+
:log_level => [ "log" , "level" ],
|
15
19
|
:file => [ "backups" , "file" ] ,
|
16
20
|
:filename => [ "backups" , "filename" ] ,
|
17
21
|
:backup_path => [ "backups" , "dir" ] ,
|
@@ -113,6 +117,32 @@ module BiblioTech
|
|
113
117
|
extract(steps, ["remotes"] + steps)
|
114
118
|
end
|
115
119
|
|
120
|
+
def log_target
|
121
|
+
target_path = local_get(:log_target)
|
122
|
+
case target_path
|
123
|
+
when "STDERR", "stderr"
|
124
|
+
return $stderr
|
125
|
+
when "STDOUT", "stdout"
|
126
|
+
return $stdout
|
127
|
+
else
|
128
|
+
require 'fileutils'
|
129
|
+
FileUtils.mkdir_p(File.dirname(target_path))
|
130
|
+
return File.open(target_path, "a")
|
131
|
+
end
|
132
|
+
rescue
|
133
|
+
warn "Trouble opening configured log file - logging to stderr"
|
134
|
+
warn $!.inspect
|
135
|
+
return $STDERR
|
136
|
+
end
|
137
|
+
|
138
|
+
def log_level
|
139
|
+
level = "debug"
|
140
|
+
optionally do
|
141
|
+
level = local_get(:log_level)
|
142
|
+
end
|
143
|
+
return BiblioTech::Logging.log_level(level)
|
144
|
+
end
|
145
|
+
|
116
146
|
def ssh_options(for_remote)
|
117
147
|
steps = steps_for(:ssh_options) + [for_remote]
|
118
148
|
steps_chain =
|
@@ -202,7 +232,7 @@ module BiblioTech
|
|
202
232
|
@backup_frequency ||= regularize_frequency(local_get(:backup_frequency))
|
203
233
|
end
|
204
234
|
|
205
|
-
def
|
235
|
+
def prune_schedules
|
206
236
|
local_get(:prune_schedule).map do |frequency, limit|
|
207
237
|
real_frequency = regularize_frequency(frequency)
|
208
238
|
unless real_frequency % backup_frequency == 0
|
@@ -215,11 +245,11 @@ module BiblioTech
|
|
215
245
|
else
|
216
246
|
Integer(limit)
|
217
247
|
end
|
218
|
-
[real_frequency, limit]
|
219
|
-
end.sort_by do |frequency, limit|
|
248
|
+
[frequency, real_frequency, limit]
|
249
|
+
end.sort_by do |freq_name, frequency, limit|
|
220
250
|
frequency
|
221
|
-
end.
|
222
|
-
|
251
|
+
end.map do |freq_name, frequency, limit|
|
252
|
+
Backups::Scheduler.new(freq_name, frequency, limit)
|
223
253
|
end
|
224
254
|
end
|
225
255
|
|
@@ -0,0 +1,36 @@
|
|
1
|
+
require 'logger'
|
2
|
+
|
3
|
+
module BiblioTech
|
4
|
+
module Logging
|
5
|
+
def self.logger
|
6
|
+
return @logger
|
7
|
+
end
|
8
|
+
|
9
|
+
def self.logger=(value)
|
10
|
+
@logger = value
|
11
|
+
end
|
12
|
+
|
13
|
+
def log
|
14
|
+
return BiblioTech::Logging.logger
|
15
|
+
end
|
16
|
+
module_function :log
|
17
|
+
|
18
|
+
def self.log_level(string)
|
19
|
+
case string
|
20
|
+
when /fatal/i
|
21
|
+
Logger::FATAL
|
22
|
+
when /error/i
|
23
|
+
Logger::ERROR
|
24
|
+
when /warn/i
|
25
|
+
Logger::WARN
|
26
|
+
when /info/i
|
27
|
+
Logger::INFO
|
28
|
+
when /debug/i
|
29
|
+
Logger::DEBUG
|
30
|
+
else
|
31
|
+
Logger::DEBUG
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
end
|
@@ -1,5 +1,6 @@
|
|
1
1
|
require 'bibliotech/application'
|
2
2
|
require 'bibliotech/backups/pruner'
|
3
|
+
require 'bibliotech/backups/scheduler'
|
3
4
|
require 'file-sandbox'
|
4
5
|
module BiblioTech
|
5
6
|
describe Backups::Pruner do
|
@@ -7,6 +8,7 @@ module BiblioTech
|
|
7
8
|
|
8
9
|
before :each do
|
9
10
|
sandbox.new :directory => "db_backups"
|
11
|
+
sandbox.new :file => '.bibliotech/config.yaml', :with_contents => "log:\n target: ../tmp/test.log"
|
10
12
|
end
|
11
13
|
|
12
14
|
let :app do
|
@@ -17,13 +19,17 @@ module BiblioTech
|
|
17
19
|
{:daily => 100}
|
18
20
|
end
|
19
21
|
|
22
|
+
let :config do
|
23
|
+
double(Config).tap do |config|
|
24
|
+
allow(config).to receive(:backup_path){ "db_backups" }
|
25
|
+
allow(config).to receive(:backup_name){ "testing" }
|
26
|
+
allow(config).to receive(:backup_frequency){ 60 * 24 }
|
27
|
+
allow(config).to receive(:schedules){ [ Backup::Scheduler.new("daily", 60 * 24, 100) ] }
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
20
31
|
let :pruner do
|
21
|
-
|
22
|
-
:frequency => "daily",
|
23
|
-
:prefix => "testing",
|
24
|
-
:keep => schedule,
|
25
|
-
:dir => "db_backups"
|
26
|
-
}})
|
32
|
+
Backups::Pruner.new(config)
|
27
33
|
end
|
28
34
|
|
29
35
|
it "should generate a filename for current time" do
|
@@ -65,6 +71,115 @@ module BiblioTech
|
|
65
71
|
expect(pruner.backup_needed?(Time.now.utc)).to be_truthy
|
66
72
|
end
|
67
73
|
end
|
74
|
+
|
75
|
+
context "marking for pruning" do
|
76
|
+
before :each do
|
77
|
+
allow(config).to receive(:prune_schedules){
|
78
|
+
[
|
79
|
+
Backups::Scheduler.new("hourlies", 60, 48),
|
80
|
+
Backups::Scheduler.new("dailies", 24 * 60, 14),
|
81
|
+
Backups::Scheduler.new("weeklies", 7 * 24 * 60, 8),
|
82
|
+
Backups::Scheduler.new("monthlies", 30 * 24 * 60, nil)
|
83
|
+
]
|
84
|
+
}
|
85
|
+
|
86
|
+
Logging.log.debug{ "Start test" }
|
87
|
+
end
|
88
|
+
|
89
|
+
it "should have schedules" do
|
90
|
+
expect(pruner.schedules.length).to eq(4)
|
91
|
+
end
|
92
|
+
|
93
|
+
it "should keep single backup" do
|
94
|
+
sandbox.new :file => "db_backups/#{pruner.filename_for(Time.now.utc)}"
|
95
|
+
|
96
|
+
expect(pruner.pruneable).to be_empty
|
97
|
+
|
98
|
+
expect(pruner.list.length).to eq(1)
|
99
|
+
pruner.list.each do |record|
|
100
|
+
expect(record.keep?).to eq(true)
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
it "should keep 48 hours of backup" do
|
105
|
+
now = Time.now.utc
|
106
|
+
(0..47).each do |interval|
|
107
|
+
sandbox.new :file => "db_backups/#{pruner.filename_for(Time.now.utc - interval * 60 * 60)}"
|
108
|
+
end
|
109
|
+
|
110
|
+
expect(pruner.pruneable).to be_empty
|
111
|
+
|
112
|
+
expect(pruner.list.length).to eq(48)
|
113
|
+
pruner.list.each do |record|
|
114
|
+
expect(record.keep?).to eq(true)
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
118
|
+
it "should prune old backups" do
|
119
|
+
now = Time.now.utc
|
120
|
+
(0..470).each do |interval|
|
121
|
+
sandbox.new :file => "db_backups/#{pruner.filename_for(now - interval * 60 * 60)}"
|
122
|
+
end
|
123
|
+
|
124
|
+
expect(pruner.pruneable.length).to eq(471 - 48 - (14 - 2) - 1) # 2 dailies hourly etc.
|
125
|
+
|
126
|
+
expect(pruner.list.length).to eq(471)
|
127
|
+
end
|
128
|
+
|
129
|
+
|
130
|
+
context "repruning" do
|
131
|
+
shared_examples_for "well mannered pruner" do
|
132
|
+
it "should not re-prune old backups" do
|
133
|
+
(0..47).each do |interval|
|
134
|
+
sandbox.new :file => "db_backups/#{pruner.filename_for(now - interval * 60 * 60)}"
|
135
|
+
end
|
136
|
+
(0..11).each do |interval|
|
137
|
+
sandbox.new :file => "db_backups/#{pruner.filename_for(now - 48 * 60 * 60 - interval * 24 * 60 * 60)}"
|
138
|
+
end
|
139
|
+
sandbox.new :file => "db_backups/#{pruner.filename_for(now - 48 * 60 * 60 - 12 * 24 * 60 * 60 - 7 * 24 * 60 * 60)}"
|
140
|
+
|
141
|
+
expect(pruner.pruneable).to be_empty
|
142
|
+
|
143
|
+
expect(pruner.list.length).to eq(48 + 12 + 1)
|
144
|
+
pruner.list.each do |record|
|
145
|
+
expect(record.keep?).to eq(true)
|
146
|
+
end
|
147
|
+
end
|
148
|
+
end
|
149
|
+
|
150
|
+
context "right now" do
|
151
|
+
it_behaves_like "well mannered pruner" do
|
152
|
+
let :now do
|
153
|
+
Time.now.utc
|
154
|
+
end
|
155
|
+
end
|
156
|
+
end
|
157
|
+
|
158
|
+
context "30 minutes ago" do
|
159
|
+
it_behaves_like "well mannered pruner" do
|
160
|
+
let :now do
|
161
|
+
Time.now.utc - 30 * 60
|
162
|
+
end
|
163
|
+
end
|
164
|
+
end
|
165
|
+
|
166
|
+
context "60 minutes ago" do
|
167
|
+
it_behaves_like "well mannered pruner" do
|
168
|
+
let :now do
|
169
|
+
Time.now.utc - 60 * 60
|
170
|
+
end
|
171
|
+
end
|
172
|
+
end
|
173
|
+
|
174
|
+
context "90 minutes ago" do
|
175
|
+
it_behaves_like "well mannered pruner" do
|
176
|
+
let :now do
|
177
|
+
Time.now.utc - 90 * 60
|
178
|
+
end
|
179
|
+
end
|
180
|
+
end
|
181
|
+
end
|
182
|
+
end
|
68
183
|
end
|
69
184
|
|
70
185
|
describe Backups::PruneList do
|
@@ -23,7 +23,7 @@ module BiblioTech::Backups
|
|
23
23
|
|
24
24
|
describe "without a limit" do
|
25
25
|
let :scheduler do
|
26
|
-
Scheduler.new(60, nil)
|
26
|
+
Scheduler.new("hourly", 60, nil)
|
27
27
|
end
|
28
28
|
|
29
29
|
context "when there's more than enough backups" do
|
@@ -39,7 +39,7 @@ module BiblioTech::Backups
|
|
39
39
|
|
40
40
|
describe "with a limit" do
|
41
41
|
let :scheduler do
|
42
|
-
Scheduler.new(60, 8)
|
42
|
+
Scheduler.new("hourly", 60, 8)
|
43
43
|
end
|
44
44
|
|
45
45
|
context "when there's just enough backups" do
|
data/spec/spec_helper.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: bibliotech
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.3.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Evan Dorn
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2014-09
|
12
|
+
date: 2014-10-09 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: caliph
|
@@ -87,6 +87,7 @@ files:
|
|
87
87
|
- lib/bibliotech/builders/postgres.rb
|
88
88
|
- lib/bibliotech/builders/mysql.rb
|
89
89
|
- lib/bibliotech/config.rb
|
90
|
+
- lib/bibliotech/logger.rb
|
90
91
|
- lib/bibliotech/command_runner.rb
|
91
92
|
- lib/bibliotech/command_generator.rb
|
92
93
|
- lib/bibliotech/rake_lib.rb
|
@@ -128,7 +129,7 @@ rdoc_options:
|
|
128
129
|
- --main
|
129
130
|
- doc/README
|
130
131
|
- --title
|
131
|
-
- bibliotech-0.
|
132
|
+
- bibliotech-0.3.0 Documentation
|
132
133
|
require_paths:
|
133
134
|
- lib/
|
134
135
|
required_ruby_version: !ruby/object:Gem::Requirement
|