Class: DatabaseFork

Inherits:
Object
  • Object
show all
Defined in:
lib/database_fork.rb

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(config_file = '.db_forks.yml', logger = Logger.new(STDOUT)) ⇒ DatabaseFork

use DatabaseFork.new.run in your post-checkout hook



19
20
21
22
# File 'lib/database_fork.rb', line 19

def initialize(config_file = '.db_forks.yml', logger = Logger.new(STDOUT))
  @config_file = config_file
  @logger = logger
end

Class Method Details

.setup_env(env, root_dir) ⇒ Object

call this at the end of your application.rb file



9
10
11
12
13
14
15
# File 'lib/database_fork.rb', line 9

def setup_env(env, root_dir)
  db_fork_var = "DATABASE_FORK_#{env}".upcase
  db_fork_file = File.join(root_dir, 'tmp', db_fork_var)
  if File.exists?(db_fork_file)
    ENV[db_fork_var] = open(db_fork_file).read.strip
  end
end

Instance Method Details

#app_connectionObject



148
149
150
# File 'lib/database_fork.rb', line 148

def app_connection
  @app_connection ||= YAML.load(ERB.new(open(File.join(File.dirname(__FILE__), '..', '..', 'config', 'database.yml')).read).result)
end

#character_setObject

could be queried from source_db:



108
109
110
# File 'lib/database_fork.rb', line 108

def character_set
  config['character_set'] || 'utf8'
end

#collationObject

could be queried from source_db:



113
114
115
# File 'lib/database_fork.rb', line 113

def collation
  config['collation'] || 'utf8_unicode_ci'
end

#configObject



156
157
158
159
160
161
162
163
164
165
166
# File 'lib/database_fork.rb', line 156

def config
  @config ||= begin
    config = {
      'check_branch_name_regex' => '^feature_',
      'ignore' => [],
      'environments' => %w(development test)
    }
    config.merge! YAML.load(open(@config_file).read) if File.exists?(@config_file)
    config
  end
end

#connection_params(env = 'development') ⇒ Object

simplify make framework agnostic



132
133
134
135
136
137
138
# File 'lib/database_fork.rb', line 132

def connection_params(env = 'development')
  @connection_params ||= if ENV['USER'] == 'vagrant'
    %Q{--user=#{app_connection[env]['username']} --password=#{app_connection[env]['password']} --socket=#{app_connection[env]['socket']}}
  else
    %Q{--user=#{app_connection[env]['username']} --password=#{app_connection[env]['password']} --host=#{app_connection[env]['host']} --port=#{app_connection[env]['port']}}
  end
end

#create_database(env = 'development') ⇒ Object



75
76
77
# File 'lib/database_fork.rb', line 75

def create_database(env = 'development')
  run_command %Q{mysql #{connection_params(env)} -e "CREATE DATABASE IF NOT EXISTS #{fork_db_name(env)} CHARACTER SET '#{character_set}' COLLATE '#{collation}';"}, "create database #{fork_db_name(env)}"
end

#create_database_fork!Object



60
61
62
63
64
65
66
67
68
69
# File 'lib/database_fork.rb', line 60

def create_database_fork!
  config['environments'].each do |env|
    log_info "creating database fork '#{fork_db_name(env)}' from #{source_db(env)}"

    create_dump(env)
    create_database(env)
    import_dump(env)
    delete_dump_file(env)
  end
end

#create_dump(env = 'development') ⇒ Object



71
72
73
# File 'lib/database_fork.rb', line 71

def create_dump(env = 'development')
  run_command %Q{mysqldump #{connection_params(env)} --routines --triggers -C #{source_db(env)} > #{dump_file_path(env)}}, "dumping #{source_db(env)}"
end

#current_branchObject



152
153
154
# File 'lib/database_fork.rb', line 152

def current_branch
  @current_branch ||= `git rev-parse --abbrev-ref HEAD`.strip.gsub('/', '_')
end

#delete_dump_file(env = 'development') ⇒ Object



83
84
85
# File 'lib/database_fork.rb', line 83

def delete_dump_file(env = 'development')
  run_command "rm #{dump_file_path(env)}", 'cleanup'
end

#dump_file_path(env = 'development') ⇒ Object



103
104
105
# File 'lib/database_fork.rb', line 103

def dump_file_path(env = 'development')
  "./tmp/dump_#{env}.sql"
end

#export_envObject



92
93
94
95
# File 'lib/database_fork.rb', line 92

def export_env
  run_command "echo #{fork_db_name('development')} > ./tmp/DATABASE_FORK_DEVELOPMENT", 'setting DATABASE_FORK_DEVELOPMENT'
  run_command "echo #{fork_db_name('test')} > ./tmp/DATABASE_FORK_TEST", 'setting DATABASE_FORK_TEST'
end

#fork_db_name(env = 'development') ⇒ Object



140
141
142
# File 'lib/database_fork.rb', line 140

def fork_db_name(env = 'development')
  "#{source_db(env)}_#{current_branch}".strip
end

#fork_exists?(env = 'development') ⇒ Boolean

Returns:

  • (Boolean)


125
126
127
128
# File 'lib/database_fork.rb', line 125

def fork_exists?(env = 'development')
  command = %Q{mysql #{connection_params[env]} -s -N -e "SHOW DATABASES LIKE '#{fork_db_name(env)}';" }
  !`#{command}`.empty?
end

#import_dump(env = 'development') ⇒ Object



79
80
81
# File 'lib/database_fork.rb', line 79

def import_dump(env = 'development')
  run_command %Q{mysql #{connection_params(env)} -C -A -D#{fork_db_name(env)} < #{dump_file_path(env)}}, 'importing dump'
end

#log_debug(message) ⇒ Object



121
122
123
# File 'lib/database_fork.rb', line 121

def log_debug(message)
  @logger.debug message
end

#log_info(message) ⇒ Object



117
118
119
# File 'lib/database_fork.rb', line 117

def log_info(message)
  @logger.info message
end

#reset_envObject



87
88
89
90
# File 'lib/database_fork.rb', line 87

def reset_env
  run_command "rm ./tmp/DATABASE_FORK_DEVELOPMENT", 'rm DATABASE_FORK_DEVELOPMENT'
  run_command "rm ./tmp/DATABASE_FORK_TEST", 'rm DATABASE_FORK_TEST'
end

#runObject



24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
# File 'lib/database_fork.rb', line 24

def run
  if config['ignore'].include?(current_branch)
    log_info 'This branch name is ignored in .db_fork.yml config. Skipping along.'
    reset_env
  elsif Regexp.new(config['check_branch_name_regex']).match(current_branch)
    log_info 'branch qualified for database forking'

    if fork_exists?
      log_info 'database fork already exists'
      export_env
    else
      log_info "Create a database fork '#{fork_db_name}'? [y|n|enter=ignore]"

      # trick to read user input:
      decision = IO.new(IO.sysopen('/dev/tty'), 'r').gets.chomp

      case decision
        when 'y'
          create_database_fork!
          export_env
        when 'n'
          # do nothing
          reset_env
        else
          config['ignore'] << current_branch
          reset_env
      end
    end
  else
    log_info 'not a feature branch. not creating database fork.'
    reset_env
  end

  save_config
end

#run_command(command, message) ⇒ Object



97
98
99
100
101
# File 'lib/database_fork.rb', line 97

def run_command(command, message)
  log_info message
  log_debug command
  `#{command}`
end

#save_configObject



168
169
170
171
172
# File 'lib/database_fork.rb', line 168

def save_config
  File.open(@config_file, 'w') do |f|
    f.puts @config.to_yaml
  end
end

#source_db(env = 'development') ⇒ Object



144
145
146
# File 'lib/database_fork.rb', line 144

def source_db(env= 'development')
  app_connection[env]['database']
end