mschuerig-branch_db 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.
- data/.gitignore +6 -0
- data/History.txt +4 -0
- data/Manifest.txt +19 -0
- data/README.rdoc +81 -0
- data/Rakefile +24 -0
- data/lib/branch_db/configuration_twiddler.rb +22 -0
- data/lib/branch_db/postgresql_switcher.rb +91 -0
- data/lib/branch_db/sqlite_switcher.rb +48 -0
- data/lib/branch_db/switcher.rb +131 -0
- data/lib/branch_db/task_helper.rb +49 -0
- data/lib/branch_db.rb +29 -0
- data/lib/tasks/db_branches.rb +49 -0
- data/test/mocks.rb +44 -0
- data/test/test_branch_db.rb +13 -0
- data/test/test_configuration_twiddler.rb +114 -0
- data/test/test_helper.rb +8 -0
- data/test/test_postgresql_switcher.rb +19 -0
- data/test/test_sqlite_switcher.rb +9 -0
- data/test/test_switcher.rb +9 -0
- metadata +109 -0
data/History.txt
ADDED
data/Manifest.txt
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
.gitignore
|
2
|
+
History.txt
|
3
|
+
Manifest.txt
|
4
|
+
README.rdoc
|
5
|
+
Rakefile
|
6
|
+
lib/branch_db.rb
|
7
|
+
lib/branch_db/configuration_twiddler.rb
|
8
|
+
lib/branch_db/postgresql_switcher.rb
|
9
|
+
lib/branch_db/sqlite_switcher.rb
|
10
|
+
lib/branch_db/switcher.rb
|
11
|
+
lib/branch_db/task_helper.rb
|
12
|
+
lib/tasks/db_branches.rb
|
13
|
+
test/mocks.rb
|
14
|
+
test/test_branch_db.rb
|
15
|
+
test/test_configuration_twiddler.rb
|
16
|
+
test/test_helper.rb
|
17
|
+
test/test_postgresql_switcher.rb
|
18
|
+
test/test_sqlite_switcher.rb
|
19
|
+
test/test_switcher.rb
|
data/README.rdoc
ADDED
@@ -0,0 +1,81 @@
|
|
1
|
+
= branch_db
|
2
|
+
|
3
|
+
* http://github.com/mschuerig/branch_db
|
4
|
+
|
5
|
+
== DESCRIPTION:
|
6
|
+
|
7
|
+
Give each git branch its own databases for ActiveRecord.
|
8
|
+
|
9
|
+
== FEATURES/PROBLEMS:
|
10
|
+
|
11
|
+
* alpha quality
|
12
|
+
* only PostgreSQL and SQLite(3) are supported yet
|
13
|
+
(adding MySQL is trivial, I'll do it when I need it)
|
14
|
+
* create, delete, copy git branch-specific databases using rake tasks
|
15
|
+
* automatic switching based on currently checked out branch
|
16
|
+
|
17
|
+
== SYNOPSIS:
|
18
|
+
|
19
|
+
Put the following block of code into config/environment.rb *before*
|
20
|
+
Rails::Initializer.run. This code ensures that the database is
|
21
|
+
automatically switched, based on the checked out git branch.
|
22
|
+
|
23
|
+
require 'branch_db/configuration_twiddler'
|
24
|
+
Rails::Configuration.class_eval do
|
25
|
+
include ::BranchDb::ConfigurationTwiddler
|
26
|
+
end
|
27
|
+
|
28
|
+
To your Rakefile or a file in lib/tasks add
|
29
|
+
|
30
|
+
require 'tasks/db_branches.rb'
|
31
|
+
|
32
|
+
Then you can use these rake tasks to manage your databases.
|
33
|
+
|
34
|
+
rake db:branches:list
|
35
|
+
List all branch databases
|
36
|
+
|
37
|
+
rake db:branches:current
|
38
|
+
Currently selected databases.
|
39
|
+
|
40
|
+
rake db:branches:create
|
41
|
+
Create empty databases for a branch. Current or BRANCH.
|
42
|
+
|
43
|
+
rake db:branches:copy
|
44
|
+
Copy databases from one branch to another.
|
45
|
+
Default is from ORIG_BRANCH=master to BRANCH=<current branch>
|
46
|
+
|
47
|
+
rake db:branches:delete
|
48
|
+
Delete databases for a branch given by BRANCH
|
49
|
+
|
50
|
+
== REQUIREMENTS:
|
51
|
+
|
52
|
+
* ActiveRecord
|
53
|
+
|
54
|
+
== INSTALL:
|
55
|
+
|
56
|
+
* sudo gem install mschuerig-branch_db
|
57
|
+
|
58
|
+
== LICENSE:
|
59
|
+
|
60
|
+
(The MIT License)
|
61
|
+
|
62
|
+
Copyright (c) 2009 Michael Schuerig
|
63
|
+
|
64
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
65
|
+
a copy of this software and associated documentation files (the
|
66
|
+
'Software'), to deal in the Software without restriction, including
|
67
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
68
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
69
|
+
permit persons to whom the Software is furnished to do so, subject to
|
70
|
+
the following conditions:
|
71
|
+
|
72
|
+
The above copyright notice and this permission notice shall be
|
73
|
+
included in all copies or substantial portions of the Software.
|
74
|
+
|
75
|
+
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
|
76
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
77
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
78
|
+
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
79
|
+
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
80
|
+
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
81
|
+
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/Rakefile
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
%w[rubygems rake rake/clean fileutils newgem rubigen].each { |f| require f }
|
2
|
+
require File.dirname(__FILE__) + '/lib/branch_db'
|
3
|
+
|
4
|
+
# Generate all the Rake tasks
|
5
|
+
# Run 'rake -T' to see list of generated tasks (from gem root directory)
|
6
|
+
$hoe = Hoe.new('branch_db', BranchDb::VERSION) do |p|
|
7
|
+
p.developer('Michael Schuerig', 'michael@schuerig.de')
|
8
|
+
p.changes = p.paragraphs_of("History.txt", 0..1).join("\n\n")
|
9
|
+
p.extra_deps = [
|
10
|
+
['activerecord','>= 2.0.2'],
|
11
|
+
]
|
12
|
+
p.extra_dev_deps = [
|
13
|
+
['newgem', ">= #{::Newgem::VERSION}"]
|
14
|
+
]
|
15
|
+
|
16
|
+
p.clean_globs |= %w[**/.DS_Store tmp *.log]
|
17
|
+
path = (p.rubyforge_name == p.name) ? p.rubyforge_name : "\#{p.rubyforge_name}/\#{p.name}"
|
18
|
+
p.remote_rdoc_dir = File.join(path.gsub(/^#{p.rubyforge_name}\/?/,''), 'rdoc')
|
19
|
+
p.rsync_args = '-av --delete --ignore-errors'
|
20
|
+
end
|
21
|
+
|
22
|
+
require 'newgem/tasks' # load /tasks/*.rake
|
23
|
+
Dir['tasks/**/*.rake'].each { |t| load t }
|
24
|
+
|
@@ -0,0 +1,22 @@
|
|
1
|
+
|
2
|
+
require 'branch_db'
|
3
|
+
|
4
|
+
module BranchDb # :nodoc
|
5
|
+
module ConfigurationTwiddler
|
6
|
+
|
7
|
+
def self.included(base)
|
8
|
+
base.send(:alias_method, :database_configuration_without_branches, :database_configuration)
|
9
|
+
base.send(:alias_method, :database_configuration, :database_configuration_with_branches)
|
10
|
+
end
|
11
|
+
|
12
|
+
def database_configuration_with_branches
|
13
|
+
dbconfig = database_configuration_without_branches
|
14
|
+
if branch = BranchDb::current_repo_branch
|
15
|
+
dbconfig.each do |env, config|
|
16
|
+
BranchDb::Switcher.create(env, config, branch).switch!
|
17
|
+
end
|
18
|
+
end
|
19
|
+
dbconfig
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,91 @@
|
|
1
|
+
|
2
|
+
require 'branch_db/switcher'
|
3
|
+
|
4
|
+
module BranchDb # :nodoc:
|
5
|
+
|
6
|
+
class PostgresqlSwitcher < Switcher
|
7
|
+
def self.can_handle?(config)
|
8
|
+
config['adapter'] == 'postgresql'
|
9
|
+
end
|
10
|
+
|
11
|
+
def current
|
12
|
+
current_branch = branch_db_exists?(@branch) ? @branch : 'master'
|
13
|
+
puts "#{@rails_env}: #{branch_db(current_branch)} (PostgreSQL)"
|
14
|
+
end
|
15
|
+
|
16
|
+
protected
|
17
|
+
|
18
|
+
def self.show_branches(rails_env, config)
|
19
|
+
super
|
20
|
+
end
|
21
|
+
|
22
|
+
def branch_db(branch)
|
23
|
+
if branch == 'master'
|
24
|
+
@config['database']
|
25
|
+
else
|
26
|
+
@config['database'].sub(/(_.+?)??(_?(#{@rails_env}))?$/, "_#{branch}\\2")
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def branch_db_exists?(branch)
|
31
|
+
existing_databases.include?(branch_db(branch))
|
32
|
+
end
|
33
|
+
|
34
|
+
def create_database(branch)
|
35
|
+
config = branch_config(branch).merge(
|
36
|
+
'encoding' => @config[:encoding] || ENV['CHARSET'] || 'utf8')
|
37
|
+
ActiveRecord::Base.establish_connection(config.merge('database' => 'postgres', 'schema_search_path' => 'public'))
|
38
|
+
ActiveRecord::Base.connection.create_database(config['database'], config)
|
39
|
+
ActiveRecord::Base.establish_connection(config)
|
40
|
+
nil
|
41
|
+
end
|
42
|
+
|
43
|
+
def drop_database(branch)
|
44
|
+
config = branch_config(branch)
|
45
|
+
ActiveRecord::Base.establish_connection(config.merge('database' => 'postgres', 'schema_search_path' => 'public'))
|
46
|
+
ActiveRecord::Base.connection.drop_database(config['database'])
|
47
|
+
@existing_databases = nil
|
48
|
+
nil
|
49
|
+
end
|
50
|
+
|
51
|
+
def copy_database(from_branch, to_branch)
|
52
|
+
dump_file = dump_branch_db(from_branch)
|
53
|
+
load_branch_db(to_branch, dump_file)
|
54
|
+
end
|
55
|
+
|
56
|
+
private
|
57
|
+
|
58
|
+
def existing_databases
|
59
|
+
@existing_databases ||=
|
60
|
+
begin
|
61
|
+
raw_dbs = `psql -l`
|
62
|
+
if $? == 0
|
63
|
+
existing_dbs = raw_dbs.split("\n").drop_while { |l| l !~ /^-/ }.drop(1).take_while { |l| l !~ /^\(/ }.map { |l| l.split('|')[0].strip }
|
64
|
+
existing_dbs.reject { |db| db =~ /^template/ }
|
65
|
+
else
|
66
|
+
raise Error, "Cannot determine existing databases."
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
def dump_branch_db(branch)
|
72
|
+
require 'tempfile'
|
73
|
+
config = branch_config(branch)
|
74
|
+
old_umask = File.umask(0077) # make created files readable only to the user
|
75
|
+
dump_file = Tempfile.new('branchdb')
|
76
|
+
`pg_dump --clean -U "#{config['username']}" --host="#{config['host']}" --port=#{config['port']} #{config['database']} > #{dump_file.path}`
|
77
|
+
raise Error, "Unable to dump database #{config['database']}." unless $? == 0
|
78
|
+
dump_file.path
|
79
|
+
ensure
|
80
|
+
File.umask(old_umask)
|
81
|
+
end
|
82
|
+
|
83
|
+
def load_branch_db(branch, dump_file)
|
84
|
+
config = branch_config(branch)
|
85
|
+
silence_stderr do
|
86
|
+
`psql -U "#{config['username']}" -f "#{dump_file}" --host="#{config['host']}" --port=#{config['port']} #{config['database']}`
|
87
|
+
end
|
88
|
+
raise Error, "Unable to load database #{config['database']}." unless $? == 0
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
|
2
|
+
require 'branch_db/switcher'
|
3
|
+
|
4
|
+
module BranchDb # :nodoc:
|
5
|
+
|
6
|
+
class SqliteSwitcher < Switcher
|
7
|
+
def self.can_handle?(config)
|
8
|
+
(config['adapter'] =~ /^sqlite/) == 0
|
9
|
+
end
|
10
|
+
|
11
|
+
def current
|
12
|
+
current_branch = branch_db_exists?(@branch) ? @branch : 'master'
|
13
|
+
puts "#{@rails_env}: #{rails_root_relative(branch_db(current_branch))} (SQLite)"
|
14
|
+
end
|
15
|
+
|
16
|
+
protected
|
17
|
+
|
18
|
+
def self.show_branches(rails_env, config)
|
19
|
+
super
|
20
|
+
end
|
21
|
+
|
22
|
+
def branch_db(branch)
|
23
|
+
if branch == 'master'
|
24
|
+
@config['database']
|
25
|
+
else
|
26
|
+
@config['database'].sub(/(.+)\./, "\\1_#{branch}.")
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def branch_db_exists?(branch)
|
31
|
+
File.exist?(File.join(RAILS_ROOT, branch_db(branch)))
|
32
|
+
end
|
33
|
+
|
34
|
+
def create_database(branch)
|
35
|
+
config = branch_config(branch)
|
36
|
+
ActiveRecord::Base.establish_connection(config)
|
37
|
+
ActiveRecord::Base.connection
|
38
|
+
end
|
39
|
+
|
40
|
+
def drop_database(branch)
|
41
|
+
FileUtils.rm_f(branch_db(branch))
|
42
|
+
end
|
43
|
+
|
44
|
+
def copy_database(from_branch, to_branch)
|
45
|
+
FileUtils.cp(branch_db(from_branch), branch_db(to_branch))
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
@@ -0,0 +1,131 @@
|
|
1
|
+
|
2
|
+
module BranchDb # :nodoc:
|
3
|
+
|
4
|
+
class Switcher
|
5
|
+
def self.which(config)
|
6
|
+
switcher = switchers.detect { |sw| sw.can_handle?(config) }
|
7
|
+
unless switcher
|
8
|
+
$stderr.puts 'Your database adapter is not supported yet.'
|
9
|
+
switcher = self # double as null switcher
|
10
|
+
end
|
11
|
+
switcher
|
12
|
+
end
|
13
|
+
|
14
|
+
def self.can_handle?(config)
|
15
|
+
raise Error, "Subclasses of BranchDb::Switcher must implement #can_handle?(config)."
|
16
|
+
end
|
17
|
+
|
18
|
+
def self.create(rails_env, config, branch, options = {})
|
19
|
+
which(config).new(rails_env, config, branch, options)
|
20
|
+
end
|
21
|
+
|
22
|
+
def self.branches(rails_env, config)
|
23
|
+
self.which(config).show_branches(rails_env, config)
|
24
|
+
end
|
25
|
+
|
26
|
+
def initialize(rails_env, config, branch, options = {})
|
27
|
+
@rails_env, @config, @branch = rails_env, config, branch
|
28
|
+
@overwrite = options[:overwrite]
|
29
|
+
end
|
30
|
+
|
31
|
+
def current
|
32
|
+
# Must be implemented in subclasses.
|
33
|
+
end
|
34
|
+
|
35
|
+
def exists?
|
36
|
+
branch_db_exists?(@branch)
|
37
|
+
end
|
38
|
+
|
39
|
+
def switch!
|
40
|
+
if exists?
|
41
|
+
@config.replace(branch_config(@branch))
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
def create_empty_database
|
46
|
+
db = branch_db(@branch)
|
47
|
+
if branch_db_exists?(@branch)
|
48
|
+
if !@overwrite
|
49
|
+
$stderr.puts "Database #{db} exists already."
|
50
|
+
return
|
51
|
+
else
|
52
|
+
puts "Dropping existing database #{db}..."
|
53
|
+
drop_database(@branch)
|
54
|
+
end
|
55
|
+
end
|
56
|
+
puts "Creating fresh database #{db}..."
|
57
|
+
create_database(@branch)
|
58
|
+
yield if block_given?
|
59
|
+
end
|
60
|
+
|
61
|
+
def delete_database
|
62
|
+
ensure_branch_db_exists!(@branch)
|
63
|
+
puts "Dropping existing database #{branch_db(@branch)}..."
|
64
|
+
drop_database(@branch)
|
65
|
+
end
|
66
|
+
|
67
|
+
def copy_from(from_branch)
|
68
|
+
ensure_branch_db_exists!(from_branch)
|
69
|
+
|
70
|
+
create_empty_database do
|
71
|
+
puts "Copying data..."
|
72
|
+
copy_database(from_branch, @branch)
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
protected
|
77
|
+
|
78
|
+
def self.show_branches(rails_env, config)
|
79
|
+
case per_branch = config['per_branch']
|
80
|
+
when true
|
81
|
+
puts "#{rails_env}: Has branch databases. Cannot determine which ones."
|
82
|
+
# when Hash
|
83
|
+
# puts "#{rails_env}:"
|
84
|
+
# per_branch.each do |db|
|
85
|
+
# puts " #{db}"
|
86
|
+
# end
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
def branch_config(branch)
|
91
|
+
@config.merge('database' => branch_db(branch))
|
92
|
+
end
|
93
|
+
|
94
|
+
def ensure_branch_db_exists!(branch)
|
95
|
+
unless branch_db_exists?(branch)
|
96
|
+
raise Error, "There is no database for the branch #{branch}."
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
def branch_db_exists?(branch)
|
101
|
+
false
|
102
|
+
end
|
103
|
+
|
104
|
+
def branch_db(branch)
|
105
|
+
# Must be implemented in subclasses.
|
106
|
+
end
|
107
|
+
|
108
|
+
def create_database(branch)
|
109
|
+
# Must be implemented in subclasses.
|
110
|
+
end
|
111
|
+
|
112
|
+
def drop_database(branch)
|
113
|
+
# Must be implemented in subclasses.
|
114
|
+
end
|
115
|
+
|
116
|
+
def copy_database(from_branch, to_branch)
|
117
|
+
# Must be implemented in subclasses.
|
118
|
+
end
|
119
|
+
|
120
|
+
private
|
121
|
+
|
122
|
+
def self.switchers
|
123
|
+
@switchers ||= []
|
124
|
+
end
|
125
|
+
|
126
|
+
def self.inherited(child)
|
127
|
+
switchers << child
|
128
|
+
end
|
129
|
+
end
|
130
|
+
end
|
131
|
+
|
@@ -0,0 +1,49 @@
|
|
1
|
+
|
2
|
+
require 'branch_db'
|
3
|
+
|
4
|
+
module BranchDb # :nodoc:
|
5
|
+
module TaskHelper
|
6
|
+
|
7
|
+
def current_branch
|
8
|
+
BranchDb::current_repo_branch(true)
|
9
|
+
end
|
10
|
+
|
11
|
+
def environment_options
|
12
|
+
{
|
13
|
+
:overwrite => ENV['OVERWRITE']
|
14
|
+
}
|
15
|
+
end
|
16
|
+
|
17
|
+
def target_branch
|
18
|
+
ENV['BRANCH'] || current_branch
|
19
|
+
end
|
20
|
+
|
21
|
+
def originating_branch
|
22
|
+
ENV['ORIG_BRANCH'] || 'master' ### TODO determine originating branch
|
23
|
+
end
|
24
|
+
|
25
|
+
def each_local_config
|
26
|
+
ActiveRecord::Base.configurations.each do |rails_env, config|
|
27
|
+
next unless config['database']
|
28
|
+
case per_branch = config['per_branch']
|
29
|
+
when true
|
30
|
+
# when Hash
|
31
|
+
else
|
32
|
+
next
|
33
|
+
end
|
34
|
+
local_database?(config) do
|
35
|
+
yield rails_env, config
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
def each_local_database(*args)
|
41
|
+
options = args.last.kind_of?(Hash) ? args.pop : {}
|
42
|
+
options = options.reverse_merge(environment_options)
|
43
|
+
branch = args[0] || target_branch
|
44
|
+
each_local_config do |rails_env, config|
|
45
|
+
yield BranchDb::Switcher.create(rails_env, config, branch, options)
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
data/lib/branch_db.rb
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
$:.unshift(File.dirname(__FILE__)) unless
|
2
|
+
$:.include?(File.dirname(__FILE__)) || $:.include?(File.expand_path(File.dirname(__FILE__)))
|
3
|
+
|
4
|
+
module BranchDb
|
5
|
+
VERSION = '0.0.1'
|
6
|
+
DEFAULT_BRANCH = 'master'
|
7
|
+
|
8
|
+
class Error < StandardError; end
|
9
|
+
|
10
|
+
def self.current_repo_branch(raise_on_error = false)
|
11
|
+
@current_repo_branch ||=
|
12
|
+
begin
|
13
|
+
raw = `git rev-parse --symbolic-full-name HEAD`
|
14
|
+
if $? == 0
|
15
|
+
raw.sub(%r{^refs/heads/}, '').chomp
|
16
|
+
elsif raise_on_error
|
17
|
+
raise Error, "Unable to determine the current repository branch."
|
18
|
+
else
|
19
|
+
# Don't raise an exception. We might be running in an exported copy.
|
20
|
+
$stderr.puts %{Unable to determine the current repository branch, assuming "#{DEFAULT_BRANCH}".}
|
21
|
+
DEFAULT_BRANCH
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
require 'branch_db/switcher'
|
28
|
+
require 'branch_db/postgresql_switcher'
|
29
|
+
require 'branch_db/sqlite_switcher'
|
@@ -0,0 +1,49 @@
|
|
1
|
+
|
2
|
+
namespace :db do
|
3
|
+
task :branches => "branches:list"
|
4
|
+
|
5
|
+
namespace :branches do
|
6
|
+
task :setup => "db:load_config" do
|
7
|
+
require 'branch_db/task_helper'
|
8
|
+
include BranchDb::TaskHelper
|
9
|
+
end
|
10
|
+
|
11
|
+
desc "List all branch databases"
|
12
|
+
task :list => :setup do
|
13
|
+
each_local_config do |rails_env, config|
|
14
|
+
BranchDb::Switcher.branches(rails_env, config)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
desc "Currently selected databases."
|
19
|
+
task :current => :setup do
|
20
|
+
each_local_database { |switcher| switcher.current }
|
21
|
+
end
|
22
|
+
|
23
|
+
desc "Create empty databases for a branch. Current or BRANCH."
|
24
|
+
task :create => :setup do
|
25
|
+
each_local_database { |switcher| switcher.create_empty_database }
|
26
|
+
end
|
27
|
+
|
28
|
+
desc "Copy databases from one branch to another. Default is from ORIG_BRANCH=master to BRANCH=<current branch>"
|
29
|
+
task :copy => :setup do
|
30
|
+
if target_branch == current_branch
|
31
|
+
$stderr.puts "Cannot copy database to itself."
|
32
|
+
else
|
33
|
+
each_local_database { |switcher| switcher.copy_from(originating_branch) }
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
desc "Delete databases for a branch given by BRANCH"
|
38
|
+
task :delete => :setup do
|
39
|
+
case target_branch
|
40
|
+
when current_branch
|
41
|
+
$stderr.puts "Cannot delete databases for the current branch."
|
42
|
+
when 'master'
|
43
|
+
$stderr.puts "Cannot delete databases for the master branch."
|
44
|
+
else
|
45
|
+
each_local_database { |switcher| switcher.delete_database }
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
data/test/mocks.rb
ADDED
@@ -0,0 +1,44 @@
|
|
1
|
+
|
2
|
+
require 'branch_db'
|
3
|
+
require 'branch_db/configuration_twiddler'
|
4
|
+
|
5
|
+
class MockConfiguration
|
6
|
+
def initialize(config)
|
7
|
+
@config = config
|
8
|
+
end
|
9
|
+
|
10
|
+
def database_configuration
|
11
|
+
@config
|
12
|
+
end
|
13
|
+
include ::BranchDb::ConfigurationTwiddler
|
14
|
+
end
|
15
|
+
|
16
|
+
module BranchDb
|
17
|
+
def self.set_branch(branch)
|
18
|
+
@branch = branch
|
19
|
+
end
|
20
|
+
def self.current_repo_branch
|
21
|
+
@branch
|
22
|
+
end
|
23
|
+
|
24
|
+
class PostgresqlSwitcher < Switcher
|
25
|
+
def dump_branch_db(*args)
|
26
|
+
@ops ||= []
|
27
|
+
@ops << [:dump_branch_db] + args
|
28
|
+
end
|
29
|
+
def load_branch_db(*args)
|
30
|
+
@ops ||= []
|
31
|
+
@ops << [:load_branch_db] + args
|
32
|
+
end
|
33
|
+
def existing_databases
|
34
|
+
%w( testit_development testit_feature_development testit_test )
|
35
|
+
end
|
36
|
+
def operations
|
37
|
+
@ops
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
def create_mock_sqlite_db(name)
|
43
|
+
File.open(File.join(RAILS_ROOT, name), 'w') { |f| f.puts 'Mock' }
|
44
|
+
end
|
@@ -0,0 +1,114 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/test_helper.rb'
|
2
|
+
|
3
|
+
require 'branch_db/configuration_twiddler'
|
4
|
+
require 'mocks'
|
5
|
+
|
6
|
+
module RealDatabaseTests
|
7
|
+
def test_master_branch
|
8
|
+
BranchDb.set_branch('master')
|
9
|
+
assert_env_db 'testit_development', 'development'
|
10
|
+
assert_env_db 'testit_test', 'test'
|
11
|
+
end
|
12
|
+
|
13
|
+
def test_branch
|
14
|
+
BranchDb.set_branch('feature')
|
15
|
+
assert_env_db 'testit_feature_development', 'development'
|
16
|
+
assert_env_db 'testit_test', 'test'
|
17
|
+
end
|
18
|
+
|
19
|
+
def test_non_existing_branch
|
20
|
+
BranchDb.set_branch('erehwon')
|
21
|
+
assert_env_db 'testit_development', 'development'
|
22
|
+
assert_env_db 'testit_test', 'test'
|
23
|
+
end
|
24
|
+
|
25
|
+
def assert_env_db(expected, env)
|
26
|
+
assert_equal expected, @mock.database_configuration[env]['database']
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
class TestConfigurationTwiddlerPostgreSQL < Test::Unit::TestCase
|
31
|
+
def setup
|
32
|
+
@mock = MockConfiguration.new({
|
33
|
+
'development' => {
|
34
|
+
'database' => 'testit_development',
|
35
|
+
'adapter' => 'postgresql',
|
36
|
+
'per_branch' => true
|
37
|
+
},
|
38
|
+
'test' => {
|
39
|
+
'database' => 'testit_test',
|
40
|
+
'adapter' => 'postgresql',
|
41
|
+
}
|
42
|
+
})
|
43
|
+
end
|
44
|
+
|
45
|
+
include RealDatabaseTests
|
46
|
+
end
|
47
|
+
|
48
|
+
=begin
|
49
|
+
### TODO
|
50
|
+
class TestConfigurationTwiddlerMysql < Test::Unit::TestCase
|
51
|
+
def setup
|
52
|
+
@mock = MockConfiguration.new({
|
53
|
+
'development' => {
|
54
|
+
'database' => 'testit_development',
|
55
|
+
'adapter' => 'mysql',
|
56
|
+
'per_branch' => true
|
57
|
+
},
|
58
|
+
'test' => {
|
59
|
+
'database' => 'testit_test',
|
60
|
+
'adapter' => 'mysql',
|
61
|
+
}
|
62
|
+
})
|
63
|
+
end
|
64
|
+
|
65
|
+
include RealDatabaseTests
|
66
|
+
end
|
67
|
+
=end
|
68
|
+
|
69
|
+
class TestConfigurationTwiddlerSQLite < Test::Unit::TestCase
|
70
|
+
def setup
|
71
|
+
@mock = MockConfiguration.new({
|
72
|
+
'development' => {
|
73
|
+
'database' => 'db/development.sqlite3',
|
74
|
+
'adapter' => 'sqlite3',
|
75
|
+
'per_branch' => true
|
76
|
+
},
|
77
|
+
'test' => {
|
78
|
+
'database' => 'db/test.sqlite3',
|
79
|
+
'adapter' => 'sqlite3'
|
80
|
+
}
|
81
|
+
})
|
82
|
+
|
83
|
+
@tmpdir = FileUtils.mkdir_p(File.join(RAILS_ROOT, 'db'))
|
84
|
+
create_mock_sqlite_db('db/development.sqlite3')
|
85
|
+
create_mock_sqlite_db('db/development_feature.sqlite3')
|
86
|
+
create_mock_sqlite_db('db/test.sqlite3')
|
87
|
+
end
|
88
|
+
|
89
|
+
def teardown
|
90
|
+
FileUtils.rm_rf(RAILS_ROOT)
|
91
|
+
end
|
92
|
+
|
93
|
+
def test_master_branch
|
94
|
+
BranchDb.set_branch('master')
|
95
|
+
assert_env_db 'db/development.sqlite3', 'development'
|
96
|
+
assert_env_db 'db/test.sqlite3', 'test'
|
97
|
+
end
|
98
|
+
|
99
|
+
def test_branch
|
100
|
+
BranchDb.set_branch('feature')
|
101
|
+
assert_env_db 'db/development_feature.sqlite3', 'development'
|
102
|
+
assert_env_db 'db/test.sqlite3', 'test'
|
103
|
+
end
|
104
|
+
|
105
|
+
def test_non_existing_branch
|
106
|
+
BranchDb.set_branch('erehwon')
|
107
|
+
assert_env_db 'db/development.sqlite3', 'development'
|
108
|
+
assert_env_db 'db/test.sqlite3', 'test'
|
109
|
+
end
|
110
|
+
|
111
|
+
def assert_env_db(expected, env)
|
112
|
+
assert_equal expected, @mock.database_configuration[env]['database']
|
113
|
+
end
|
114
|
+
end
|
data/test/test_helper.rb
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/test_helper.rb'
|
2
|
+
|
3
|
+
require 'mocks'
|
4
|
+
|
5
|
+
class TestPostgresqlSwitcher < Test::Unit::TestCase
|
6
|
+
def setup
|
7
|
+
@config = {
|
8
|
+
'development' => {
|
9
|
+
'database' => 'testit_development',
|
10
|
+
'adapter' => 'postgresql'
|
11
|
+
}
|
12
|
+
}
|
13
|
+
@switcher = BranchDb::PostgresqlSwitcher.new('development', @config, 'feature')
|
14
|
+
end
|
15
|
+
|
16
|
+
def test_branches
|
17
|
+
puts BranchDb::PostgresqlSwitcher.branches('development', @config['development'])
|
18
|
+
end
|
19
|
+
end
|
metadata
ADDED
@@ -0,0 +1,109 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: mschuerig-branch_db
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Michael Schuerig
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
|
12
|
+
date: 2009-04-08 00:00:00 -07:00
|
13
|
+
default_executable:
|
14
|
+
dependencies:
|
15
|
+
- !ruby/object:Gem::Dependency
|
16
|
+
name: activerecord
|
17
|
+
type: :runtime
|
18
|
+
version_requirement:
|
19
|
+
version_requirements: !ruby/object:Gem::Requirement
|
20
|
+
requirements:
|
21
|
+
- - ">="
|
22
|
+
- !ruby/object:Gem::Version
|
23
|
+
version: 2.0.2
|
24
|
+
version:
|
25
|
+
- !ruby/object:Gem::Dependency
|
26
|
+
name: newgem
|
27
|
+
type: :development
|
28
|
+
version_requirement:
|
29
|
+
version_requirements: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: 1.3.0
|
34
|
+
version:
|
35
|
+
- !ruby/object:Gem::Dependency
|
36
|
+
name: hoe
|
37
|
+
type: :development
|
38
|
+
version_requirement:
|
39
|
+
version_requirements: !ruby/object:Gem::Requirement
|
40
|
+
requirements:
|
41
|
+
- - ">="
|
42
|
+
- !ruby/object:Gem::Version
|
43
|
+
version: 1.8.0
|
44
|
+
version:
|
45
|
+
description: Give each git branch its own databases for ActiveRecord.
|
46
|
+
email:
|
47
|
+
- michael@schuerig.de
|
48
|
+
executables: []
|
49
|
+
|
50
|
+
extensions: []
|
51
|
+
|
52
|
+
extra_rdoc_files:
|
53
|
+
- History.txt
|
54
|
+
- Manifest.txt
|
55
|
+
- README.rdoc
|
56
|
+
files:
|
57
|
+
- .gitignore
|
58
|
+
- History.txt
|
59
|
+
- Manifest.txt
|
60
|
+
- README.rdoc
|
61
|
+
- Rakefile
|
62
|
+
- lib/branch_db.rb
|
63
|
+
- lib/branch_db/configuration_twiddler.rb
|
64
|
+
- lib/branch_db/postgresql_switcher.rb
|
65
|
+
- lib/branch_db/sqlite_switcher.rb
|
66
|
+
- lib/branch_db/switcher.rb
|
67
|
+
- lib/branch_db/task_helper.rb
|
68
|
+
- lib/tasks/db_branches.rb
|
69
|
+
- test/mocks.rb
|
70
|
+
- test/test_branch_db.rb
|
71
|
+
- test/test_configuration_twiddler.rb
|
72
|
+
- test/test_helper.rb
|
73
|
+
- test/test_postgresql_switcher.rb
|
74
|
+
- test/test_sqlite_switcher.rb
|
75
|
+
- test/test_switcher.rb
|
76
|
+
has_rdoc: false
|
77
|
+
homepage: http://github.com/mschuerig/branch_db
|
78
|
+
post_install_message:
|
79
|
+
rdoc_options:
|
80
|
+
- --main
|
81
|
+
- README.rdoc
|
82
|
+
require_paths:
|
83
|
+
- lib
|
84
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
85
|
+
requirements:
|
86
|
+
- - ">="
|
87
|
+
- !ruby/object:Gem::Version
|
88
|
+
version: "0"
|
89
|
+
version:
|
90
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
91
|
+
requirements:
|
92
|
+
- - ">="
|
93
|
+
- !ruby/object:Gem::Version
|
94
|
+
version: "0"
|
95
|
+
version:
|
96
|
+
requirements: []
|
97
|
+
|
98
|
+
rubyforge_project: branch_db
|
99
|
+
rubygems_version: 1.2.0
|
100
|
+
signing_key:
|
101
|
+
specification_version: 2
|
102
|
+
summary: Give each git branch its own databases for ActiveRecord.
|
103
|
+
test_files:
|
104
|
+
- test/test_sqlite_switcher.rb
|
105
|
+
- test/test_helper.rb
|
106
|
+
- test/test_configuration_twiddler.rb
|
107
|
+
- test/test_postgresql_switcher.rb
|
108
|
+
- test/test_branch_db.rb
|
109
|
+
- test/test_switcher.rb
|