switch_db 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.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: a3c9a1dc6785a1fe8b0783cee362b5a0fbd54844
4
+ data.tar.gz: 0e3c756f7e024416663442cfda3372f3e545576a
5
+ SHA512:
6
+ metadata.gz: fd6dc0c3c9161877d9ab267076bbf28f03012e121def85faf6073a1e613384406e5ad44fe607e7ba644dd0f4f9c5b438132cb52a4918fed44f035fa97a819274
7
+ data.tar.gz: 0d1c497e4d59e5452528ee5ec80266e9fca150efd4f5a3541d8ce751998a89ff6b69504f3f5047f268f0a64f6d03f08c1bb8e1050780c4d587cb2c06d8f82c4c
data/.gitignore ADDED
@@ -0,0 +1,13 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
10
+
11
+ # rspec failure tracking
12
+ .rspec_status
13
+ switch_db*.gem
data/.rspec ADDED
@@ -0,0 +1,3 @@
1
+ --format documentation
2
+ --require spec_helper
3
+ --color
data/.rubocop.yml ADDED
@@ -0,0 +1,111 @@
1
+ AllCops:
2
+ TargetRubyVersion: 2.4
3
+ DisplayCopNames: true
4
+ Metrics/BlockNesting:
5
+ Enabled: false
6
+ Metrics/ClassLength:
7
+ Enabled: false
8
+ Metrics/CyclomaticComplexity:
9
+ Enabled: false
10
+ Metrics/ParameterLists:
11
+ Enabled: false
12
+ Metrics/PerceivedComplexity:
13
+ Enabled: false
14
+ Metrics/AbcSize:
15
+ Enabled: false
16
+ Metrics/LineLength:
17
+ Enabled: false
18
+ Metrics/MethodLength:
19
+ Enabled: false
20
+ Metrics/BlockLength:
21
+ Enabled: false # blockの長さは機会的に判断するより、reviewで都度判断したほうがいいと思うため
22
+ Metrics/ModuleLength:
23
+ Enabled: false # moduleも同様
24
+ Style/AsciiComments:
25
+ Enabled: false
26
+ Style/BlockDelimiters:
27
+ Exclude:
28
+ - 'spec/**/*'
29
+ Style/RaiseArgs:
30
+ Enabled: false
31
+ Style/Lambda:
32
+ Enabled: false
33
+ Lint/AmbiguousRegexpLiteral:
34
+ Enabled: false
35
+ Lint/HandleExceptions :
36
+ Enabled: false
37
+ Style/StringLiterals:
38
+ Enabled: false
39
+ Style/Documentation:
40
+ Enabled: false
41
+ Layout/MultilineOperationIndentation:
42
+ Enabled: false
43
+ Style/AccessorMethodName:
44
+ Enabled: false
45
+ Style/PredicateName:
46
+ Enabled: false
47
+ Style/NestedTernaryOperator:
48
+ Enabled: false
49
+ Style/AndOr:
50
+ Exclude:
51
+ - 'app/controllers/**/*'
52
+ Rails/Date:
53
+ EnforcedStyle: flexible
54
+ Style/BlockDelimiters:
55
+ Enabled: false
56
+ Style/RescueModifier:
57
+ Enabled: false
58
+ Style/DoubleNegation:
59
+ Enabled: false
60
+ Lint/AmbiguousOperator:
61
+ Enabled: false
62
+ Style/FrozenStringLiteralComment:
63
+ Enabled: false
64
+ # 空のメソッドは1行で書けとか言われるが、可読性優先で複数行にしたい場合もある
65
+ Style/EmptyMethod:
66
+ Enabled: false
67
+ # rescue nil とか書きたい
68
+ Style/RescueModifier:
69
+ Enabled: false
70
+ # Gemfileの内容をABC順に並べろとか言われる…
71
+ Bundler/OrderedGems:
72
+ Enabled: false
73
+ # 100_000などとする桁数
74
+ Style/NumericLiterals:
75
+ MinDigits: 7
76
+ Style/GuardClause:
77
+ Enabled: false
78
+
79
+ # できる限りAsciiで書くが、英語だと意味が揺れる場合は許容する
80
+ # https://github.com/moneyforward/mf_cloud_platform/pull/636
81
+ Style/AsciiIdentifiers:
82
+ Exclude:
83
+ - 'spec/models/journal_branch_side_spec.rb'
84
+ - 'spec/models/journal_branch_spec.rb'
85
+
86
+ Layout/AlignParameters:
87
+ EnforcedStyle: with_fixed_indentation
88
+
89
+ Layout/MultilineMethodCallIndentation:
90
+ EnforcedStyle: indented
91
+
92
+ # 変数が nil であることを考慮していないのでよくない
93
+ # 検知された変数を吟味して `#to_i` を適切に追記できるなら使っても良い
94
+ Style/NumericPredicate:
95
+ Enabled: false
96
+
97
+ # DSLに対して適用した場合、可読性が悪くなることがあるため使用しない
98
+ Lint/AmbiguousBlockAssociation:
99
+ Enabled: false
100
+
101
+ # Hash#merge!の代わりに代入を強要するが、merge!の方が可読性がよいケースもあるため使用しない
102
+ Performance/RedundantMerge:
103
+ Enabled: false
104
+
105
+ # class/module定義時にネスト方法を強要するが、あまり重要ではないので使用しない
106
+ Style/ClassAndModuleChildren:
107
+ Enabled: false
108
+
109
+ # $LAST_MATCH_INFOなどは require 'english' をする必要がある
110
+ Style/SpecialGlobalVars:
111
+ Enabled: false
data/.ruby-version ADDED
@@ -0,0 +1 @@
1
+ 2.3.5
data/.travis.yml ADDED
@@ -0,0 +1,5 @@
1
+ sudo: false
2
+ language: ruby
3
+ rvm:
4
+ - 2.3.5
5
+ before_install: gem install bundler -v 1.15.4
data/Gemfile ADDED
@@ -0,0 +1,12 @@
1
+ source "https://rubygems.org"
2
+
3
+ git_source(:github) { |repo_name| "https://github.com/#{repo_name}" }
4
+
5
+ # Specify your gem's dependencies in switch_db.gemspec
6
+ gemspec
7
+
8
+ gem 'pry'
9
+ gem 'guard'
10
+ gem 'guard-rspec'
11
+ gem 'rubocop'
12
+ gem 'guard-rubocop'
data/Guardfile ADDED
@@ -0,0 +1,17 @@
1
+ guard :rspec, cmd: 'bundle exec rspec' do
2
+ require 'guard/rspec/dsl'
3
+ dsl = Guard::RSpec::Dsl.new(self)
4
+
5
+ # RSpec files
6
+ rspec = dsl.rspec
7
+ watch(rspec.spec_files)
8
+
9
+ # Ruby files
10
+ ruby = dsl.ruby
11
+ dsl.watch_spec_files_for(ruby.lib_files)
12
+ end
13
+
14
+ guard :rubocop do
15
+ watch(/.+\.rb$/)
16
+ watch(%r{(?:.+/)?\.rubocop\.yml$}) { |m| File.dirname(m[0]) }
17
+ end
data/LICENSE.txt ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2017 alpaca-tc
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,77 @@
1
+ # SwitchDb
2
+
3
+ A command-line interface for a database dumpfile
4
+
5
+ ## Installation
6
+
7
+ ```sh
8
+ git clone https://github.com/alpaca-tc/switch_db
9
+ cd switch_db
10
+
11
+ bundle install
12
+ bundle exec rake install
13
+ ```
14
+
15
+ ## Usage
16
+
17
+ ```
18
+ # Show dumpfile list
19
+ switch_db list
20
+
21
+ # Change user_name and as so on
22
+ switch_db config [key:value...]
23
+
24
+ # Remove dumpfile
25
+ switch_db rm <name>
26
+
27
+ # Store database
28
+ switch_db store <name> --database_names [database_name,database_name...]
29
+
30
+ # Restore database
31
+ switch_db restore <name>
32
+ ```
33
+
34
+ Example
35
+
36
+ ```
37
+ # Show list
38
+ $ switch_db list
39
+ 0: initial_database
40
+ 1: new_feature
41
+ 2: latest_database
42
+
43
+ $ echo $(git rev-parse --abbrev-ref HEAD)
44
+ master
45
+
46
+ # Store databases
47
+ $ switch_db store $(git rev-parse --abbrev-ref HEAD) --database_names application_development,application_test
48
+ Stored database a 'application_development'
49
+ Stored database a 'application_test'
50
+
51
+ $ switch_db list
52
+ 0: initial_database
53
+ 1: new_feature
54
+ 2: latest_database
55
+ 3: master
56
+
57
+ # Restore databases
58
+ $ switch_db restore master
59
+ Restored database a 'application_development'
60
+ Restored database a 'application_test'
61
+
62
+ # Set default username and password
63
+ switch_db config user_name:root password:password
64
+ ```
65
+
66
+ ## Development
67
+
68
+ After checking out the repo, run `bundle install` to install dependencies. Then, run `rake spec` to run the tests.
69
+ To install this gem onto your local machine, run `bundle exec rake install`.
70
+
71
+ ## Contributing
72
+
73
+ Bug reports and pull requests are welcome on GitHub at https://github.com/alpaca-tc/switch_db.
74
+
75
+ ## License
76
+
77
+ The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
data/Rakefile ADDED
@@ -0,0 +1,6 @@
1
+ require "bundler/gem_tasks"
2
+ require "rspec/core/rake_task"
3
+
4
+ RSpec::Core::RakeTask.new(:spec)
5
+
6
+ task default: :spec
data/bin/console ADDED
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "bundler/setup"
4
+ require "switch_db"
5
+
6
+ # You can add fixtures and/or initialization code here to make experimenting
7
+ # with your gem easier. You can also use a different console, if you like.
8
+
9
+ # (If you use this, don't forget to add pry to your Gemfile!)
10
+ # require "pry"
11
+ # Pry.start
12
+
13
+ require "irb"
14
+ IRB.start(__FILE__)
data/bin/setup ADDED
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+ set -vx
5
+
6
+ bundle install
7
+
8
+ # Do any other automated setup that you need to do here
data/bin/switch_db ADDED
@@ -0,0 +1,10 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../Gemfile', __FILE__)
4
+ require 'bundler/setup' if File.exist?(ENV['BUNDLE_GEMFILE'])
5
+
6
+ $LOAD_PATH.unshift(File.expand_path('../../lib', __FILE__))
7
+
8
+ require 'switch_db'
9
+
10
+ SwitchDb.run(ARGV)
@@ -0,0 +1,20 @@
1
+ module SwitchDb
2
+ class Cli
3
+ class << self
4
+ def run!(command, arguments = {})
5
+ command_class = command_for(command)
6
+ reference_set = ReferenceSet.load_file(SwitchDb.configuration.reference_set_file_full_path)
7
+ command_class.new(reference_set: reference_set).run(arguments)
8
+ reference_set.write_reference_set
9
+ end
10
+
11
+ private
12
+
13
+ def command_for(command)
14
+ Command.const_get(Utils.classify(command.to_s))
15
+ rescue NameError
16
+ raise CommandNotFound, "#{command} is unknown command."
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,13 @@
1
+ module SwitchDb
2
+ module Command
3
+ class Base
4
+ def initialize(reference_set:)
5
+ @reference_set = reference_set
6
+ end
7
+
8
+ def run(_arguments = {})
9
+ raise NotImplementedError, 'not implemented yet'
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,19 @@
1
+ require 'fileutils'
2
+
3
+ module SwitchDb
4
+ module Command
5
+ class Config < Base
6
+ def run(arguments = {})
7
+ arguments.each do |key, value|
8
+ if SwitchDb.configuration.configuration_keys.include?(key.to_sym)
9
+ SwitchDb.configuration.public_send("#{key}=", value)
10
+ else
11
+ raise SwitchDb::UnknownConfigurationKey, "Unknown configuration given (#{key})"
12
+ end
13
+ end
14
+
15
+ SwitchDb.configuration.write_configuration_file
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,19 @@
1
+ module SwitchDb
2
+ module Command
3
+ class List < Base
4
+ def run(*)
5
+ length = @reference_set.references.size.to_s.length
6
+
7
+ @reference_set.references.each_with_index do |(_, reference), index|
8
+ puts "#{format_index(length, index)}: #{reference.name}"
9
+ end
10
+ end
11
+
12
+ private
13
+
14
+ def format_index(length, index)
15
+ format("%#{length}d", index)
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,29 @@
1
+ module SwitchDb
2
+ module Command
3
+ class Restore < Base
4
+ attr_reader :reference
5
+
6
+ def run(name:, **)
7
+ reference = @reference_set.references[name.to_s]
8
+
9
+ unless reference
10
+ $stderr.puts("#{name} not exists")
11
+ exit
12
+ end
13
+
14
+ database = SwitchDb::Database.current_database
15
+
16
+ threads = reference.database_paths.map do |database_name, database_path|
17
+ Thread.new do
18
+ database.drop_database(database_name)
19
+ database.create_database(database_name)
20
+ database.import_database(database_name, database_path)
21
+ puts "Restored database a '#{database_name}'"
22
+ end
23
+ end
24
+
25
+ threads.each(&:join)
26
+ end
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,16 @@
1
+ require 'fileutils'
2
+
3
+ module SwitchDb
4
+ module Command
5
+ class Rm < Base
6
+ def run(name:, **)
7
+ reference = @reference_set.references[name.to_s]
8
+ return unless reference
9
+
10
+ @reference_set.remove_reference(reference)
11
+ puts "Deleted reference a (#{reference.name})"
12
+ FileUtils.rm_rf(reference.full_path)
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,29 @@
1
+ require 'fileutils'
2
+
3
+ module SwitchDb
4
+ module Command
5
+ class Store < Base
6
+ def run(name:, database_names: [])
7
+ reference = SwitchDb::Reference.new(name: name, database_names: database_names)
8
+ duplicated = @reference_set.references.key?(reference.name)
9
+
10
+ FileUtils.mkdir_p(reference.full_path)
11
+
12
+ reference.database_paths.each do |database_name, database_path|
13
+ next if duplicated && !overwrite?(reference)
14
+
15
+ SwitchDb::Database.current_database.dump_database(database_name, database_path)
16
+ puts "Stored database a '#{database_name}'"
17
+ end
18
+
19
+ @reference_set.add_reference(reference)
20
+ end
21
+
22
+ private
23
+
24
+ def overwrite?(reference)
25
+ Dialog.question?("Overwrite existing stored file? (#{reference.name})")
26
+ end
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,10 @@
1
+ module SwitchDb
2
+ module Command
3
+ require 'switch_db/command/base'
4
+ require 'switch_db/command/list'
5
+ require 'switch_db/command/store'
6
+ require 'switch_db/command/restore'
7
+ require 'switch_db/command/rm'
8
+ require 'switch_db/command/config'
9
+ end
10
+ end
@@ -0,0 +1,68 @@
1
+ require 'pathname'
2
+ require 'fileutils'
3
+
4
+ module SwitchDb
5
+ class Configuration
6
+ attr_reader :config_file
7
+ attr_reader :cache_dir
8
+ attr_accessor :reference_set_file
9
+ attr_accessor :user_name
10
+ attr_accessor :password
11
+
12
+ def initialize
13
+ @config_file = 'config.yml'
14
+ @reference_set_file = 'reference_set.yml'
15
+ @cache_dir = Pathname.new(File.expand_path('~/.cache/switch_db'))
16
+ @user_name = 'root'
17
+ @password = nil
18
+
19
+ load_from_config_file(configuration_full_path)
20
+ end
21
+
22
+ def reference_set_file_full_path
23
+ cache_dir.join(reference_set_file)
24
+ end
25
+
26
+ def to_h
27
+ {
28
+ reference_set_file: reference_set_file,
29
+ user_name: user_name,
30
+ password: password
31
+ }
32
+ end
33
+
34
+ def write_configuration_file
35
+ FileUtils.mkdir_p(File.dirname(configuration_full_path))
36
+ File.write(configuration_full_path, to_h.to_yaml)
37
+ end
38
+
39
+ def configuration_keys
40
+ %i[
41
+ reference_set_file
42
+ user_name
43
+ password
44
+ ]
45
+ end
46
+
47
+ private
48
+
49
+ def configuration_full_path
50
+ cache_dir.join(config_file)
51
+ end
52
+
53
+ def load_from_config_file(path)
54
+ yaml = YAML.load_file(path)
55
+
56
+ yaml.each do |key, value|
57
+ case key
58
+ when 'cache_dir'
59
+ @cache_dir = Pathname.new(File.expand_path(cache_dir))
60
+ else
61
+ public_send("#{key}=", value) if respond_to?("#{key}=")
62
+ end
63
+ end
64
+ rescue Errno::ENOENT
65
+ # Do nothing
66
+ end
67
+ end
68
+ end
@@ -0,0 +1,21 @@
1
+ module SwitchDb
2
+ module Database
3
+ module Abstract
4
+ def drop_database(_database_name)
5
+ raise NotImplementedError
6
+ end
7
+
8
+ def create_database(_database_name)
9
+ raise NotImplementedError
10
+ end
11
+
12
+ def import_database(_database_name, _database_path)
13
+ raise NotImplementedError
14
+ end
15
+
16
+ def dump_database(_database_name, _output_path)
17
+ raise NotImplementedError
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,34 @@
1
+ module SwitchDb
2
+ module Database
3
+ module Mysql
4
+ extend Abstract
5
+
6
+ class << self
7
+ def drop_database(database_name)
8
+ `mysql #{user_and_password} --execute="DROP DATABASE #{database_name}"`
9
+ end
10
+
11
+ def create_database(database_name)
12
+ `mysql #{user_and_password} --execute="CREATE DATABASE #{database_name}"`
13
+ end
14
+
15
+ def import_database(database_name, database_path)
16
+ `mysql #{user_and_password} #{database_name} < #{database_path}`
17
+ end
18
+
19
+ def dump_database(database_name, output_path)
20
+ `mysqldump #{user_and_password} #{database_name} > #{output_path}`
21
+ end
22
+
23
+ private
24
+
25
+ def user_and_password
26
+ arguments = ["-u #{SwitchDb.configuration.user_name}"]
27
+ arguments.push("-p#{SwitchDb.configuration.password}") if SwitchDb.configuration.password
28
+
29
+ arguments.join(' ')
30
+ end
31
+ end
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,11 @@
1
+ module SwitchDb
2
+ module Database
3
+ require 'switch_db/database/abstract'
4
+ require 'switch_db/database/mysql'
5
+
6
+ # Currently, supported database is only 'mysql'
7
+ def self.current_database
8
+ SwitchDb::Database::Mysql
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,15 @@
1
+ module SwitchDb
2
+ module Dialog
3
+ # rubocop:disable Performance/RegexpMatch
4
+ def self.question?(message)
5
+ loop do
6
+ print(message + ' y/n ')
7
+ answer = $stdin.gets.strip
8
+
9
+ return true if /\A(?:y|yes)\z/i =~ answer
10
+ return false if /\A(?:n|no)\z/i =~ answer
11
+ end
12
+ end
13
+ # rubocop:enable Performance/RegexpMatch
14
+ end
15
+ end
@@ -0,0 +1,5 @@
1
+ module SwitchDb
2
+ class SwitchDbError < StandardError; end
3
+ class CommandNotFound < SwitchDbError; end
4
+ class UnknownConfigurationKey < SwitchDbError; end
5
+ end
@@ -0,0 +1,115 @@
1
+ require 'optparse'
2
+
3
+ module SwitchDb
4
+ class OptionParser
5
+ REQUIRED_KEYS = {
6
+ config: [],
7
+ store: %i[name --database_names],
8
+ restore: [:name],
9
+ rm: [:name],
10
+ list: []
11
+ }.freeze
12
+
13
+ def initialize(argv)
14
+ @original_argv = argv
15
+ @options = {}
16
+ end
17
+
18
+ def parse!(argv = @original_argv.clone)
19
+ @options[:command] = argv[0]
20
+
21
+ # rubocop:disable Lint/EmptyWhen
22
+ case @options[:command]
23
+ when 'list'
24
+ # Do nothing
25
+ when 'config'
26
+ parse_config_argv(argv[1..-1])
27
+ when 'store', 'restore', 'rm'
28
+ @options[:name] = argv[1]
29
+ parse_argv(argv)
30
+ else
31
+ parse_argv(argv)
32
+ end
33
+ # rubocop:enable Lint/EmptyWhen
34
+
35
+ validate_option!
36
+
37
+ @options
38
+ end
39
+
40
+ private
41
+
42
+ def validate_option!
43
+ required_keys = REQUIRED_KEYS[@options[:command].to_s.to_sym]
44
+
45
+ if required_keys.nil?
46
+ print_error("'#{@options[:command]}' is unknown command.")
47
+ elsif required_keys.include?(:name) && @options[:name].to_s.empty?
48
+ print_error("<name> is empty.")
49
+ else
50
+ required_keys.select { |name| name.to_s.start_with?('--') }.each do |name|
51
+ name = name.to_s.gsub(/^--/, '').to_sym
52
+ value = @options[name]
53
+ print_error("'--#{name}' option is empty.") if value.nil? || value.empty?
54
+ end
55
+ end
56
+ end
57
+
58
+ def parse_config_argv(argv)
59
+ key_values = argv.select { |key_value| key_value.include?(':') }
60
+
61
+ key_values.each do |key_value|
62
+ key, value = key_value.split(':')
63
+ @options[key.to_sym] = value.to_s
64
+ end
65
+ end
66
+
67
+ def parse_argv(argv)
68
+ argv.each_with_index do |raw_key, index|
69
+ next unless raw_key.start_with?('--')
70
+
71
+ key = raw_key.gsub(/^--/, '')
72
+ next_index = index + 1
73
+ value = argv[next_index] unless argv[next_index].to_s.start_with?('--')
74
+ parse_option(key, value)
75
+ end
76
+ end
77
+
78
+ def parse_option(option_name, value)
79
+ case option_name
80
+ when 'database_names'
81
+ @options[:database_names] = value.to_s.split(/(?:,|\s+)/)
82
+ when 'help'
83
+ puts banner
84
+ exit
85
+ else
86
+ print_error("'--#{option_name}' is unknown option.")
87
+ end
88
+ end
89
+
90
+ def print_error(message)
91
+ $stderr.puts("switch_db: #{message} See 'switch_db --help'")
92
+ exit
93
+ end
94
+
95
+ def banner
96
+ <<~BANNER
97
+ switch_db v#{SwitchDb::VERSION}
98
+
99
+ switch_db is a database dumpfile manager. This is a basic help message.
100
+ Usage:
101
+ switch_db list
102
+ switch_db config [key:value...]
103
+ switch_db rm <name>
104
+ switch_db store <name> --database_names [database_name,database_name...]
105
+ switch_db restore <name>
106
+
107
+ Examples:
108
+ switch_db rm feature1
109
+ switch_db config user_name:root password:secret_password
110
+ switch_db store feature1 --database_names db1,db2,db3
111
+ switch_db restore feature1
112
+ BANNER
113
+ end
114
+ end
115
+ end
@@ -0,0 +1,31 @@
1
+ module SwitchDb
2
+ class Reference
3
+ attr_reader :name, :database_names
4
+
5
+ def initialize(name:, database_names: [])
6
+ @name = name
7
+ @database_names = database_names
8
+ end
9
+
10
+ def path
11
+ Utils.escape_filename(@name)
12
+ end
13
+
14
+ def full_path
15
+ SwitchDb.configuration.cache_dir.join(path)
16
+ end
17
+
18
+ def database_paths
19
+ @database_names.map { |database_name|
20
+ [database_name, full_path.join("#{Utils.escape_filename(database_name)}.sql")]
21
+ }.to_h
22
+ end
23
+
24
+ def to_h
25
+ {
26
+ name: name,
27
+ database_names: database_names
28
+ }
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,55 @@
1
+ require 'fileutils'
2
+ require 'yaml'
3
+
4
+ module SwitchDb
5
+ class ReferenceSet
6
+ attr_reader :configuration_path, :references
7
+
8
+ def initialize(configuration_path)
9
+ @configuration_path = configuration_path
10
+ @references = {}
11
+ end
12
+
13
+ def self.load_file(configuration_path)
14
+ new(configuration_path).tap do |instance|
15
+ yaml = YAML.load_file(configuration_path)
16
+
17
+ (yaml[:references] || []).map do |reference|
18
+ reference = Reference.new(
19
+ name: reference[:name],
20
+ database_names: reference[:database_names]
21
+ )
22
+
23
+ instance.add_reference(reference)
24
+ end
25
+ end
26
+ rescue Errno::ENOENT
27
+ new(configuration_path)
28
+ end
29
+
30
+ def add_reference(reference)
31
+ @references[reference.name] = reference
32
+ end
33
+
34
+ def remove_reference(reference)
35
+ @references.delete(reference.name)
36
+ end
37
+
38
+ def write_reference_set
39
+ FileUtils.mkdir_p(configuration_directory)
40
+ File.write(@configuration_path, to_h.to_yaml)
41
+ end
42
+
43
+ private
44
+
45
+ def to_h
46
+ {
47
+ references: references.values.map(&:to_h)
48
+ }
49
+ end
50
+
51
+ def configuration_directory
52
+ File.dirname(@configuration_path)
53
+ end
54
+ end
55
+ end
@@ -0,0 +1,13 @@
1
+ module SwitchDb
2
+ module Utils
3
+ def self.escape_filename(name)
4
+ name.to_s
5
+ end
6
+
7
+ def self.classify(name)
8
+ name.split(/[\-_]/).map { |part|
9
+ "#{part[0].upcase}#{part[1..-1].downcase}"
10
+ }.join
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,3 @@
1
+ module SwitchDb
2
+ VERSION = '0.1.0'.freeze
3
+ end
data/lib/switch_db.rb ADDED
@@ -0,0 +1,35 @@
1
+ require 'switch_db/cli'
2
+ require 'switch_db/exceptions'
3
+ require 'switch_db/configuration'
4
+ require 'switch_db/dialog'
5
+ require 'switch_db/option_parser'
6
+ require 'switch_db/reference'
7
+ require 'switch_db/reference_set'
8
+ require 'switch_db/utils'
9
+ require 'switch_db/version'
10
+ require 'switch_db/command'
11
+ require 'switch_db/database'
12
+
13
+ module SwitchDb
14
+ def self.configuration
15
+ @configuration ||= Configuration.new
16
+ end
17
+
18
+ def self.run(argv)
19
+ option_parser = SwitchDb::OptionParser.new(argv)
20
+ args = option_parser.parse!
21
+ command = args.delete(:command)
22
+
23
+ Cli.run!(command, args)
24
+ rescue SwitchDb::CommandNotFound => error
25
+ $stderr.puts(error.message)
26
+ $stderr.puts
27
+ $stderr.puts(option_parser.option_parser.banner)
28
+ rescue SwitchDb::UnknownConfigurationKey => error
29
+ $stderr.puts(error.message)
30
+ $stderr.puts
31
+ $stderr.puts("Allowed configuration keys are #{configuration.configuration_keys.map(&:to_s)}")
32
+ $stderr.puts
33
+ $stderr.puts(option_parser.option_parser.banner)
34
+ end
35
+ end
data/switch_db.gemspec ADDED
@@ -0,0 +1,29 @@
1
+ # coding: utf-8
2
+
3
+ lib = File.expand_path("../lib", __FILE__)
4
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
5
+ require 'switch_db/version'
6
+
7
+ Gem::Specification.new do |spec|
8
+ spec.name = 'switch_db'
9
+ spec.version = SwitchDb::VERSION
10
+ spec.authors = ['alpaca-tc']
11
+ spec.email = ['alpaca-tc@alpaca.tc']
12
+
13
+ spec.summary = 'A command-line interface for a database dumpfile'
14
+ spec.description = 'This cli provides a way to load/dump database in development environment'
15
+ spec.homepage = 'https://github.com/alpaca-tc/switch_db'
16
+ spec.license = 'MIT'
17
+
18
+ spec.files = `git ls-files -z`.split("\x0").reject do |f|
19
+ f.match(%r{^(spec)/})
20
+ end
21
+
22
+ spec.bindir = 'bin'
23
+ spec.executables = %w[switch_db]
24
+ spec.require_paths = ['lib']
25
+
26
+ spec.add_development_dependency 'bundler', '~> 1.15'
27
+ spec.add_development_dependency 'rake', '~> 10.0'
28
+ spec.add_development_dependency 'rspec', '~> 3.0'
29
+ end
metadata ADDED
@@ -0,0 +1,121 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: switch_db
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - alpaca-tc
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2017-11-21 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.15'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.15'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '10.0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '10.0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rspec
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '3.0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '3.0'
55
+ description: This cli provides a way to load/dump database in development environment
56
+ email:
57
+ - alpaca-tc@alpaca.tc
58
+ executables:
59
+ - switch_db
60
+ extensions: []
61
+ extra_rdoc_files: []
62
+ files:
63
+ - ".gitignore"
64
+ - ".rspec"
65
+ - ".rubocop.yml"
66
+ - ".ruby-version"
67
+ - ".travis.yml"
68
+ - Gemfile
69
+ - Guardfile
70
+ - LICENSE.txt
71
+ - README.md
72
+ - Rakefile
73
+ - bin/console
74
+ - bin/setup
75
+ - bin/switch_db
76
+ - lib/switch_db.rb
77
+ - lib/switch_db/cli.rb
78
+ - lib/switch_db/command.rb
79
+ - lib/switch_db/command/base.rb
80
+ - lib/switch_db/command/config.rb
81
+ - lib/switch_db/command/list.rb
82
+ - lib/switch_db/command/restore.rb
83
+ - lib/switch_db/command/rm.rb
84
+ - lib/switch_db/command/store.rb
85
+ - lib/switch_db/configuration.rb
86
+ - lib/switch_db/database.rb
87
+ - lib/switch_db/database/abstract.rb
88
+ - lib/switch_db/database/mysql.rb
89
+ - lib/switch_db/dialog.rb
90
+ - lib/switch_db/exceptions.rb
91
+ - lib/switch_db/option_parser.rb
92
+ - lib/switch_db/reference.rb
93
+ - lib/switch_db/reference_set.rb
94
+ - lib/switch_db/utils.rb
95
+ - lib/switch_db/version.rb
96
+ - switch_db.gemspec
97
+ homepage: https://github.com/alpaca-tc/switch_db
98
+ licenses:
99
+ - MIT
100
+ metadata: {}
101
+ post_install_message:
102
+ rdoc_options: []
103
+ require_paths:
104
+ - lib
105
+ required_ruby_version: !ruby/object:Gem::Requirement
106
+ requirements:
107
+ - - ">="
108
+ - !ruby/object:Gem::Version
109
+ version: '0'
110
+ required_rubygems_version: !ruby/object:Gem::Requirement
111
+ requirements:
112
+ - - ">="
113
+ - !ruby/object:Gem::Version
114
+ version: '0'
115
+ requirements: []
116
+ rubyforge_project:
117
+ rubygems_version: 2.5.2.1
118
+ signing_key:
119
+ specification_version: 4
120
+ summary: A command-line interface for a database dumpfile
121
+ test_files: []