bibliotech 0.1.0

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.
Files changed (40) hide show
  1. checksums.yaml +7 -0
  2. data/bin/bibliotech +5 -0
  3. data/doc/example_config_file.yml +58 -0
  4. data/doc/todo.txt +19 -0
  5. data/lib/bibliotech/application.rb +95 -0
  6. data/lib/bibliotech/backups/file_record.rb +16 -0
  7. data/lib/bibliotech/backups/prune_list.rb +58 -0
  8. data/lib/bibliotech/backups/pruner.rb +71 -0
  9. data/lib/bibliotech/backups/scheduler.rb +49 -0
  10. data/lib/bibliotech/builders/database.rb +25 -0
  11. data/lib/bibliotech/builders/file.rb +75 -0
  12. data/lib/bibliotech/builders/gzip.rb +51 -0
  13. data/lib/bibliotech/builders/mysql.rb +35 -0
  14. data/lib/bibliotech/builders/postgres.rb +37 -0
  15. data/lib/bibliotech/builders.rb +43 -0
  16. data/lib/bibliotech/cli.rb +24 -0
  17. data/lib/bibliotech/command_generator.rb +86 -0
  18. data/lib/bibliotech/command_runner.rb +36 -0
  19. data/lib/bibliotech/compression/bzip2.rb +6 -0
  20. data/lib/bibliotech/compression/gzip.rb +6 -0
  21. data/lib/bibliotech/compression/sevenzip.rb +5 -0
  22. data/lib/bibliotech/compression.rb +35 -0
  23. data/lib/bibliotech/config.rb +269 -0
  24. data/lib/bibliotech/rake_lib.rb +82 -0
  25. data/lib/bibliotech.rb +7 -0
  26. data/spec/bibliotech/backup_pruner_spec.rb +58 -0
  27. data/spec/bibliotech/backup_scheduler_spec.rb +108 -0
  28. data/spec/bibliotech/command_generator/mysql_spec.rb +170 -0
  29. data/spec/bibliotech/command_generator/postgres_spec.rb +180 -0
  30. data/spec/bibliotech/command_generator_spec.rb +99 -0
  31. data/spec/bibliotech/command_runner_spec.rb +50 -0
  32. data/spec/bibliotech/compression/bunzip2_spec.rb +9 -0
  33. data/spec/bibliotech/compression/bzip2_spec.rb +9 -0
  34. data/spec/bibliotech/compression/gzip_spec.rb +9 -0
  35. data/spec/bibliotech/compression/sevenzip_spec.rb +9 -0
  36. data/spec/bibliotech/compression_spec.rb +28 -0
  37. data/spec/bibliotech/config_spec.rb +151 -0
  38. data/spec/gem_test_suite.rb +0 -0
  39. data/spec/spec_helper.rb +2 -0
  40. metadata +150 -0
@@ -0,0 +1,170 @@
1
+ require 'spec_helper'
2
+ require 'pry'
3
+
4
+ module BiblioTech
5
+ describe CommandGenerator, "for mysql" do
6
+ let :config do
7
+ Config.new(nil).tap do |config|
8
+ config.hash = config_hash
9
+ end
10
+ end
11
+ let :generator do
12
+ CommandGenerator.new(config)
13
+ end
14
+ let( :db_name ) { "db_name" }
15
+ let( :username ) { "user_name" }
16
+ let( :password ) { "password123" }
17
+ let( :host ) { "127.0.0.1" }
18
+ let( :filename ) { "export.sql" }
19
+ let( :path ) { "/some/path" }
20
+
21
+ let :base_config_hash do
22
+ { "database_config" => {
23
+ "adapter" => :mysql,
24
+ "database" => db_name,
25
+ "username" => username
26
+ }}
27
+ end
28
+ let(:config_hash){ base_config_hash }
29
+
30
+ let(:options){ {} }
31
+
32
+ def first_cmd
33
+ command.commands[0]
34
+ end
35
+
36
+ def second_cmd
37
+ command.commands[1]
38
+ end
39
+
40
+ describe :export do
41
+ subject :command do
42
+ generator.export(options)
43
+ end
44
+
45
+ context 'with username and database' do
46
+ context 'and password' do
47
+ let :config_hash do
48
+ #binding.pry
49
+ base_config_hash.tap do |hash|
50
+ hash["database_config"]["password"] = password
51
+ end
52
+ end
53
+
54
+ it { is_expected.to be_a(Caliph::CommandLine) }
55
+ it { expect(command.executable).to eq('mysqldump') }
56
+ it { expect(command.options).to eq(["-u #{username}", "--password='#{password}'", "#{db_name}"]) }
57
+ end
58
+
59
+ context 'and hostname' do
60
+ let :config_hash do
61
+ base_config_hash.tap do |hash|
62
+ hash["database_config"]["host"] = host
63
+ end
64
+ end
65
+
66
+ it { expect(command.options).to eq(["-h #{host}", "-u #{username}", "#{db_name}"]) }
67
+ end
68
+
69
+ context 'plus filename and path' do
70
+ let :options do
71
+ {:backups => { :filename => filename, :dir => path}}
72
+ end
73
+
74
+ context 'and compressor' do
75
+ let :options do
76
+ { :backups => {
77
+ :filename => filename,
78
+ :dir => path,
79
+ :compress => :gzip
80
+ }}
81
+ end
82
+
83
+ it { expect(command).to be_a(Caliph::PipelineChain) }
84
+ it { expect(second_cmd.redirections).to eq([ "1>#{path}/#{filename}.gz" ]) }
85
+
86
+ context "first command" do
87
+ it { expect(first_cmd.executable).to eq('mysqldump') }
88
+ it { expect(first_cmd.options).to eq(["-u #{username}", "#{db_name}"]) }
89
+ end
90
+ context "second command" do
91
+ it { expect(second_cmd.executable).to eq('gzip') }
92
+ end
93
+ end
94
+ end
95
+
96
+ context 'with the whole shebang' do
97
+ let :options do
98
+ { :backups => { :filename => filename, :dir => path, :compress => :gzip} }
99
+ end
100
+ let :config_hash do
101
+ base_config_hash.tap do |hash|
102
+ hash["database_config"].merge!( "host" => host, "password" => password)
103
+ end
104
+ end
105
+
106
+ it { expect(second_cmd.redirections).to eq(["1>#{path}/#{filename}.gz"]) }
107
+
108
+ context "first command" do
109
+ it { expect(first_cmd.executable).to eq("mysqldump") }
110
+ it { expect(first_cmd.options).to eq(["-h #{host}", "-u #{username}", "--password='#{password}'", "#{db_name}"]) }
111
+ end
112
+
113
+ context "second command" do
114
+ it { expect(second_cmd.executable).to eq('gzip') }
115
+ end
116
+ end
117
+ end
118
+ end
119
+
120
+
121
+ describe :import do
122
+ let :command do
123
+ generator.import(options)
124
+ end
125
+
126
+ subject do
127
+ command
128
+ end
129
+
130
+ context 'with username, database, file, and path' do
131
+ let :options do
132
+ { :backups => { :filename => filename, :dir => path }}
133
+ end
134
+
135
+ it { expect(command).to be_a(Caliph::CommandLine) }
136
+
137
+ it { expect(command.redirections).to eq(["0<#{path}/#{filename}"]) }
138
+ it { expect(command.executable).to eq('mysql')}
139
+ it { expect(command.options).to eq(["-u #{username}", db_name ]) }
140
+
141
+ context "plus password" do
142
+ let :config_hash do
143
+ base_config_hash.tap do |hash|
144
+ hash["database_config"]["password"] = password
145
+ end
146
+ end
147
+
148
+ it { expect(command.options).to eq(["-u #{username}","--password='#{password}'", "#{db_name}"]) }
149
+
150
+ context 'and compressor' do
151
+ let :options do
152
+ { :backups => {
153
+ :filename => filename + '.gz',
154
+ :dir => path,
155
+ :compress => :gzip
156
+ } }
157
+ end
158
+
159
+ it { expect(command).to be_a(Caliph::PipelineChain) }
160
+ it { expect(first_cmd.executable).to eq('gunzip') }
161
+ it { expect(first_cmd.options).to eq(["#{path}/#{filename}.gz"]) }
162
+ end
163
+ end
164
+ end
165
+ end
166
+
167
+
168
+
169
+ end
170
+ end
@@ -0,0 +1,180 @@
1
+ require 'spec_helper'
2
+
3
+ module BiblioTech
4
+ describe CommandGenerator do
5
+ let :generator do
6
+ CommandGenerator.new(config)
7
+ end
8
+
9
+ let (:db_name){ "db_name" }
10
+ let (:username){ "user_name" }
11
+ let (:password){ "password123" }
12
+ let (:host){ "127.0.0.1" }
13
+ let (:filename){ "export.pg" }
14
+ let (:path){ "/some/path" }
15
+
16
+
17
+ let (:base_options){{}}
18
+
19
+ let :base_config_hash do
20
+ { "database_config" =>
21
+ {
22
+ "adapter" => :postgres,
23
+ "database" => db_name,
24
+ "username" => username
25
+ }
26
+ }
27
+
28
+ end
29
+
30
+ let(:config_hash){ base_config_hash }
31
+ let(:options){ base_options }
32
+
33
+ let :config do
34
+ Config.new(nil).tap do |config|
35
+ config.hash = config_hash
36
+ end
37
+ end
38
+
39
+ def first_cmd
40
+ command.commands[0]
41
+ end
42
+
43
+ def second_cmd
44
+ command.commands[1]
45
+ end
46
+
47
+ describe :export do
48
+ let :command do
49
+ generator.export(options)
50
+ end
51
+
52
+ subject do
53
+ command
54
+ end
55
+
56
+ context 'with username and database' do
57
+ let :config_hash do
58
+ base_config_hash
59
+ end
60
+
61
+ context 'and password' do
62
+ let :config_hash do
63
+ base_config_hash.tap do |hash|
64
+ hash["database_config"]["password"] = password
65
+ end
66
+ end
67
+
68
+ it { is_expected.to be_a(Caliph::CommandLine) }
69
+ it { expect(command.executable).to eq('pg_dump') }
70
+ it { expect(command.options).to eq(["-Fc", "-U #{username}", "#{db_name}"]) }
71
+ it { expect(command.env['PGPASSWORD']).to eq(password) }
72
+ end
73
+
74
+ context 'and hostname' do
75
+ let :config_hash do
76
+ base_config_hash.tap do |hash|
77
+ hash["database_config"]["host"] = host
78
+ end
79
+ end
80
+
81
+ it { expect(command.options).to eq(["-Fc", "-h #{host}", "-U #{username}", "#{db_name}"]) }
82
+ end
83
+
84
+ context 'plus filename and path and compressor' do
85
+ let :options do
86
+ base_options.merge( :backups => {
87
+ :dir => path,
88
+ :filename => filename,
89
+ :compress => :gzip
90
+ })
91
+ end
92
+
93
+ it { expect(command).to be_a(Caliph::PipelineChain) }
94
+ it { expect(command.commands[1].redirections).to eq([ "1>#{path}/#{filename}.gz" ]) }
95
+
96
+ context "first command" do
97
+ it { expect(first_cmd.executable).to eq('pg_dump') }
98
+ it { expect(first_cmd.options).to eq(["-Fc", "-U #{username}", "#{db_name}"]) }
99
+ end
100
+ context "second command" do
101
+ it { expect(second_cmd.executable).to eq('gzip') }
102
+ end
103
+ end
104
+
105
+ context 'with the whole shebang' do
106
+ let :options do
107
+ base_options.merge( :backups => {
108
+ :filename => filename,
109
+ :dir => path,
110
+ :compress => :gzip
111
+ })
112
+ end
113
+ let :config_hash do
114
+ base_config_hash.tap do |hash|
115
+ hash["database_config"] = hash["database_config"].merge({ "host" => host, "password" => password })
116
+ end
117
+ end
118
+
119
+ it { expect(second_cmd.redirections).to eq(["1>#{path}/#{filename}.gz"]) }
120
+
121
+ context "first command" do
122
+ it { expect(first_cmd.executable).to eq("pg_dump") }
123
+ it { expect(first_cmd.options).to eq(["-Fc", "-h #{host}", "-U #{username}", "#{db_name}"]) }
124
+ it { expect(first_cmd.env['PGPASSWORD']).to eq(password) }
125
+ end
126
+
127
+ context "second command" do
128
+ it { expect(second_cmd.executable).to eq('gzip') }
129
+ end
130
+ end
131
+ end
132
+ end
133
+
134
+
135
+ describe :import do
136
+ let :command do
137
+ generator.import(options)
138
+ end
139
+
140
+ subject do
141
+ command
142
+ end
143
+
144
+ context 'with username, database, file, and path' do
145
+ let :options do
146
+ base_options.merge(:backups => { :filename => filename, :dir => path })
147
+ end
148
+
149
+ it { expect(command.redirections).to eq(["0<#{path}/#{filename}"]) }
150
+ it { expect(command.executable).to eq('pg_restore')}
151
+ it { expect(command.options).to eq(["-U #{username}", "-d #{db_name}" ]) }
152
+
153
+ context "plus password" do
154
+ let :config_hash do
155
+ base_config_hash.tap do |hash|
156
+ hash["database_config"]["password"] = password
157
+ end
158
+ end
159
+
160
+ it { expect(command.options).to eq(["-U #{username}", "-d #{db_name}"]) }
161
+ it { expect(command.env['PGPASSWORD']).to eq(password) }
162
+
163
+ context 'and compressor' do
164
+ let :options do
165
+ base_options.merge(:backups => {
166
+ :filename => filename + '.gz',
167
+ :dir => path,
168
+ :compressor => :gzip
169
+ })
170
+ end
171
+
172
+ it { expect(command).to be_a(Caliph::PipelineChain) }
173
+ it { expect(first_cmd.executable).to eq('gunzip') }
174
+ it { expect(first_cmd.options).to eq(["#{path}/#{filename}.gz"]) }
175
+ end
176
+ end
177
+ end
178
+ end
179
+ end
180
+ end
@@ -0,0 +1,99 @@
1
+ require 'spec_helper'
2
+ require 'bibliotech/application'
3
+
4
+ module BiblioTech
5
+ describe CommandGenerator do
6
+ describe "class methods", :pending => true do
7
+ describe "adapter lookup" do
8
+ class CommandOne < CommandGenerator; end;
9
+ class CommandTwo < CommandGenerator; end;
10
+ let :class_1 do CommandOne end
11
+ let :class_2 do CommandTwo end
12
+ let :config do { :adapter => :type_1 } end
13
+ let :return_adapter do double(CommandGenerator) end
14
+
15
+ before do
16
+ CommandGenerator.class_eval do
17
+ @adapter_registry = nil
18
+ end
19
+ end
20
+
21
+ context "with one class registered" do
22
+ before do
23
+ CommandGenerator.register(:type_1, CommandOne)
24
+ end
25
+ it "should list single supported adapter" do
26
+ expect(CommandGenerator.supported_adapters()).to eq([:type_1])
27
+ end
28
+ it "should return the correct adapter, instantiated with the config" do
29
+ expect(CommandOne).to receive(:new).and_return(return_adapter)
30
+ expect(CommandGenerator.for(config)).to eq(return_adapter)
31
+ end
32
+ end
33
+
34
+ context "with two classes registered" do
35
+ before do
36
+ CommandGenerator.register(:type_1, CommandOne)
37
+ CommandGenerator.register(:type_2, CommandTwo)
38
+ end
39
+ it "should return a single registered class" do
40
+ expect(CommandGenerator.supported_adapters()).to include(:type_1, :type_2)
41
+ end
42
+ end
43
+ context "with one class registered twice" do
44
+ before do
45
+ CommandGenerator.register(:type_1, CommandOne)
46
+ CommandGenerator.register(:type_1a, CommandOne)
47
+ end
48
+ it "should list single supported adapter" do
49
+ expect(CommandGenerator.supported_adapters()).to eq([:type_1, :type_1a])
50
+ end
51
+ end
52
+ end
53
+ end
54
+
55
+ describe "skeleton methods" do
56
+ let :generator do
57
+ CommandGenerator.new(config)
58
+ end
59
+
60
+ let :app do
61
+ Application.new
62
+ end
63
+
64
+ let :config do
65
+ app.config
66
+ end
67
+
68
+ it "should produce a remote_cli command" do
69
+ expect(generator.remote_cli("staging", "latest").command).to match(/\Assh.*-- '.*bibliotech latest'\z/)
70
+ end
71
+
72
+ it "should produce a fetch command" do
73
+ expect(generator.fetch("staging", "latest.sql.gz").command).to match(/\Ascp.*@.*latest\.sql\.gz.*latest\.sql\.gz\z/)
74
+ end
75
+
76
+ it "should produce a push command" do
77
+ expect(generator.push("staging", "latest.sql.gz").command).to match(/\Ascp.*latest\.sql\.gz.*@.*latest\.sql\.gz\z/)
78
+ end
79
+
80
+ it "should raise_error an error when calling wipe" do
81
+ expect do
82
+ generator.wipe()
83
+ end.to raise_error(NotImplementedError)
84
+ end
85
+
86
+ it "should raise_error an error when calling delete" do
87
+ expect do
88
+ generator.delete()
89
+ end.to raise_error(NotImplementedError)
90
+ end
91
+
92
+ it "should raise_error an error when calling create" do
93
+ expect do
94
+ generator.create()
95
+ end.to raise_error(NotImplementedError)
96
+ end
97
+ end
98
+ end
99
+ end
@@ -0,0 +1,50 @@
1
+ require 'spec_helper'
2
+ require 'bibliotech/command_runner'
3
+
4
+
5
+ module BiblioTech
6
+ describe CommandRunner do
7
+ let :config do
8
+ double(Config,
9
+ :db_config => {},
10
+ :environment => :development
11
+ )
12
+ end
13
+
14
+ let :generator do
15
+ double(CommandGenerator,
16
+ :export => 'export command'
17
+ )
18
+ end
19
+
20
+ let :command do "some cli command" end
21
+
22
+ let :shell do
23
+ double("Caliph::Shell")
24
+ end
25
+
26
+ let :runner do
27
+ CommandRunner.new(config).tap do |runner|
28
+ runner.shell = shell
29
+ end
30
+ end
31
+
32
+ before do
33
+ allow(CommandGenerator).to receive(:for).and_return(generator)
34
+ end
35
+
36
+ describe "single commands" do
37
+ it 'should do export' do
38
+ expect(generator).to receive(:export).and_return(command)
39
+ expect(shell).to receive(:run).with(command)
40
+ runner.export('path/to/file')
41
+ end
42
+
43
+ it 'should do import' do
44
+ expect(generator).to receive(:import).and_return(command)
45
+ expect(shell).to receive(:run).with(command)
46
+ runner.import('path/to/file')
47
+ end
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,9 @@
1
+ require 'spec_helper'
2
+
3
+ module BiblioTech
4
+ describe Compression::Bzip2 do
5
+ # TODO
6
+ end
7
+ end
8
+
9
+
@@ -0,0 +1,9 @@
1
+ require 'spec_helper'
2
+
3
+ module BiblioTech
4
+ describe Compression::Bzip2 do
5
+ # TODO
6
+ end
7
+ end
8
+
9
+
@@ -0,0 +1,9 @@
1
+ require 'spec_helper'
2
+
3
+ module BiblioTech
4
+ describe Compression::Gzip do
5
+ # TODO
6
+ end
7
+ end
8
+
9
+
@@ -0,0 +1,9 @@
1
+ require 'spec_helper'
2
+
3
+ module BiblioTech
4
+ describe Compression::SevenZip do
5
+ # TODO
6
+ end
7
+ end
8
+
9
+
@@ -0,0 +1,28 @@
1
+ require 'spec_helper'
2
+
3
+ module BiblioTech
4
+ describe Compression do
5
+
6
+ let :generator do
7
+ double(CommandGenerator)
8
+ end
9
+
10
+ describe 'for' do
11
+ it do
12
+ expect(Compression.for("my_archive.sql.gz", generator)).to be_a(Compression::Gzip)
13
+ end
14
+
15
+ it do
16
+ expect(Compression.for("my_archive.sql.bz2", generator)).to be_a(Compression::Bzip2)
17
+ end
18
+
19
+ it do
20
+ expect(Compression.for("my_archive.sql.7z", generator)).to be_a(Compression::SevenZip)
21
+ end
22
+
23
+ it do
24
+ expect(Compression.for("my_archive.sql", generator)).to equal(generator)
25
+ end
26
+ end
27
+ end
28
+ end