omniscient 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 ADDED
@@ -0,0 +1,4 @@
1
+ *.gem
2
+ .bundle
3
+ Gemfile.lock
4
+ pkg/*
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source "http://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in dbme.gemspec
4
+ gemspec
data/README.markdown ADDED
@@ -0,0 +1,34 @@
1
+ Omniscient is a gem that automatically dumps a MySQL database in a remote server
2
+ via SSH, copies the dumped file to localhost via SCP and imports it, overwriting the local
3
+ database (or table).
4
+
5
+ It'll be very useful for those that are developing using more than one machine and
6
+ don't want to dump and clone data manually all the time.
7
+
8
+ Getting Started
9
+ ===============
10
+
11
+ In your console, type the following, where aliasname is a name you choose
12
+ (i.e. home_computer, work etc):
13
+
14
+ $ omniscient clone aliasname
15
+
16
+ A setup will begin. The data will be save to ~/.omni_config.yml
17
+
18
+ Now that Omniscient knows where to connect, run the following command again
19
+
20
+ $ omniscient clone aliasname
21
+
22
+ You can clone a 'custom_dbname' database from that host.
23
+
24
+ $ omniscient clone aliasname -d custom_dbname
25
+
26
+ Troubleshoting
27
+ ==============
28
+
29
+ Tested on Mac OS X.
30
+
31
+ Credits
32
+ =======
33
+
34
+ Alexandre de Oliveira
data/Rakefile ADDED
@@ -0,0 +1,9 @@
1
+ require 'bundler'
2
+ require 'rake/testtask'
3
+ Bundler::GemHelper.install_tasks
4
+
5
+ # just 'rake test'
6
+ Rake::TestTask.new do |t|
7
+ # t.libs << "lib"
8
+ t.test_files = Dir["test/**/test*.rb"]
9
+ end
data/bin/omniscient ADDED
@@ -0,0 +1,20 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ $:.unshift File.expand_path('../../lib/', __FILE__)
4
+
5
+ require "omniscient"
6
+ require "command"
7
+ require "shell/shell.rb"
8
+
9
+ command = Shell::Parser::get_command ARGV
10
+
11
+ unless command.empty? then
12
+ command_file = File.expand_path('../../lib/omniscient/command/'+command+'.rb', __FILE__)
13
+
14
+ # checks if class file exists
15
+ if File.exists? command_file then
16
+ require command_file
17
+ command = command.capitalize
18
+ command_obj = Omniscient::Command.const_get(command).new(ARGV)
19
+ end
20
+ end
data/lib/omniscient.rb ADDED
@@ -0,0 +1,11 @@
1
+ $:.unshift File.expand_path('../omniscient/', __FILE__)
2
+
3
+ require 'configuration'
4
+ require 'shell/shell'
5
+ require 'command'
6
+
7
+ module Omniscient
8
+ DUMP_FILENAME = '.omni_dump.sql'
9
+ DUMP_LOCAL_PATH = '~/'+DUMP_FILENAME
10
+ DUMP_REMOTE_PATH = DUMP_FILENAME
11
+ end
@@ -0,0 +1,48 @@
1
+ module Omniscient
2
+ module Adapter
3
+ class MySQL
4
+ attr_accessor :attributes
5
+ def initialize( config )
6
+ @attributes = config
7
+ end
8
+
9
+ def method_missing( name, *args, &block )
10
+ if args.empty? && block.nil?
11
+ if @attributes.has_key?(name.to_s)
12
+ @attributes[name.to_s]
13
+ elsif @attributes.has_key?(name.to_sym)
14
+ @attributes[name.to_sym]
15
+ else
16
+ nil
17
+ end
18
+ else
19
+ nil
20
+ end
21
+ end
22
+
23
+ def access_statements
24
+ str = ''
25
+ str << ' -u '+self.user unless self.user.nil?
26
+ str << ' '+self.database unless self.database.nil?
27
+ str << ' -p'+self.password unless self.password.empty?
28
+ str
29
+ end
30
+
31
+ def dump
32
+ str = 'mysqldump'
33
+ str << access_statements
34
+ str << ' '+self.table unless self.database.nil? || self.table.nil?
35
+ str << ' --single-transaction'
36
+ str << ' > .omni_dump.sql'
37
+ str
38
+ end
39
+
40
+ def import
41
+ str = 'mysql'
42
+ str << access_statements
43
+ str << ' < '+Omniscient::DUMP_LOCAL_PATH
44
+ str
45
+ end
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,32 @@
1
+ module Omniscient
2
+
3
+ module Command
4
+
5
+ class Run
6
+ def initialize argv = ''
7
+ @argv = argv
8
+
9
+ @configurations = Omniscient::Configuration.new
10
+
11
+ if Shell::Parser.is_option "help", argv
12
+ help if self.respond_to?('help')
13
+ exit
14
+ end
15
+
16
+ if( self.respond_to?('run') )
17
+ run
18
+ elsif( self.respond_to?('help') )
19
+ help
20
+ end
21
+
22
+ end
23
+
24
+ def request_configuration
25
+ @configurations.configuration @configurations.questions(:alias_name => @alias_name)
26
+ end
27
+
28
+ end
29
+
30
+ end
31
+
32
+ end
@@ -0,0 +1,68 @@
1
+ require 'yaml'
2
+
3
+ module Omniscient
4
+
5
+ module Command
6
+
7
+ class Clone < Omniscient::Command::Run
8
+
9
+ def run
10
+
11
+ @alias_name = Shell::Parser.get_arguments(@argv).first || ""
12
+
13
+ has_conf = load_configuration_by_alias(@alias_name)
14
+ unless has_conf
15
+ request_configuration
16
+ end
17
+
18
+ database = Shell::Parser.get_option_value('d', @argv) || nil
19
+ @configurations['mysql']['database'] = database unless database.empty?
20
+
21
+ require 'ssh'
22
+ require 'scp'
23
+ require 'adapters/mysql'
24
+ @ssh = Omniscient::Ssh.new(@configurations['ssh'])
25
+ @scp = Omniscient::Scp.new(@configurations['ssh'])
26
+ @mysql = Omniscient::Adapter::MySQL.new(@configurations['mysql'])
27
+
28
+ # Dumps remotely
29
+ command_to_issue = "#{@ssh.connect} '#{@mysql.dump}'"
30
+ puts "Running => #{command_to_issue}"
31
+ exit unless system command_to_issue
32
+
33
+ # Copies dumped data
34
+ command_to_issue = "#{@scp.connect}:"+Omniscient::DUMP_REMOTE_PATH+" "+Omniscient::DUMP_LOCAL_PATH
35
+ puts "Running => #{command_to_issue}"
36
+ exit unless system command_to_issue
37
+
38
+ # Imports data
39
+ command_to_issue = "#{@mysql.import}"
40
+ puts "Running => #{command_to_issue}"
41
+ exit unless system command_to_issue
42
+
43
+ end
44
+
45
+ def load_configuration_by_alias alias_name
46
+ return false unless alias_name
47
+ return false unless File.exist?(File.expand_path('~/.omniscient_conf.yml'))
48
+
49
+ config_file = File.new(File.expand_path('~/.omniscient_conf.yml'), 'r')
50
+ existing_configurations = YAML::load(config_file.read)
51
+ if existing_configurations.kind_of?(Hash) && existing_configurations.has_key?(alias_name)
52
+ @configurations = existing_configurations[alias_name]
53
+ true
54
+ else
55
+ false
56
+ end
57
+
58
+ end
59
+
60
+ def help
61
+ puts 'Help is missing.'
62
+ end
63
+
64
+ end
65
+
66
+ end
67
+
68
+ end
@@ -0,0 +1,83 @@
1
+ require 'yaml'
2
+
3
+ module Omniscient
4
+ class Configuration
5
+ def initialize( conf = {} )
6
+ @configuration = conf
7
+ end
8
+
9
+ def method_missing( name, *args, &block )
10
+ if args.empty? && block.nil? && @attributes.has_key?(name)
11
+ @attributes[name.to_sym]
12
+ else
13
+ nil
14
+ end
15
+ end
16
+
17
+ def questions informations
18
+
19
+ custom_alias = informations[:alias_name].nil? ? nil : informations[:alias_name]
20
+
21
+ unless custom_alias.nil?
22
+ puts "No configuration found for #{custom_alias}. You need to setup a remote machine.\n"
23
+ @configuration = { custom_alias => {} }
24
+ else
25
+ puts "No configuration found. You need to setup a remote machine.\n"
26
+ print "Type an name for this remote machine [a word you want]: "
27
+ custom_alias = Shell::Input.text.downcase
28
+ end
29
+
30
+ @configuration = { custom_alias => {} }
31
+ @configuration[custom_alias]['ssh'] = {}
32
+ @configuration[custom_alias]['mysql'] = {}
33
+
34
+ unless @configuration[custom_alias]['ssh'].has_key?('address')
35
+ print "SSH address [i.e. username@some_ip]: "
36
+ @configuration[custom_alias]['ssh']['address'] = Shell::Input.text
37
+ end
38
+
39
+ unless @configuration[custom_alias]['ssh'].has_key?('port')
40
+ print "SSH port [leave empty for default]: "
41
+ ssh_port = Shell::Input.text
42
+ @configuration[custom_alias]['ssh']['port'] = ssh_port.empty? ? 22 : ssh_port.empty?
43
+ end
44
+
45
+ unless @configuration[custom_alias]['mysql'].has_key?('user')
46
+ print "Database's username [default's 'root']: "
47
+ mysql_user = Shell::Input.text
48
+ @configuration[custom_alias]['mysql']['user'] = mysql_user.empty? ? 'root' : mysql_user
49
+ end
50
+
51
+ unless @configuration[custom_alias]['mysql'].has_key?('password')
52
+ system "stty -echo"
53
+ print "Database's password [leave it blank if none is needed]: "
54
+ mysql_password = Shell::Input.text
55
+ system "stty echo"
56
+ print "\n"
57
+ @configuration[custom_alias]['mysql']['password'] = mysql_password.empty? ? '' : mysql_password
58
+ end
59
+
60
+ unless @configuration[custom_alias]['mysql'].has_key?('database')
61
+ print "The default database name you will work with: "
62
+ mysql_db = Shell::Input.text
63
+ @configuration[custom_alias]['mysql']['database'] = mysql_db.empty? ? '' : mysql_db
64
+ end
65
+
66
+ config_file = File.new(File.expand_path('~/.omniscient_conf.yml'), 'a+')
67
+ existing_configurations = YAML::load(config_file.read)
68
+
69
+ if existing_configurations && existing_configurations.kind_of?(Hash)
70
+ @configuration = existing_configurations.merge(@configuration)
71
+ end
72
+ config_file.truncate(0)
73
+ config_file.puts YAML::dump(@configuration)
74
+ config_file.close
75
+
76
+ puts "\nDone."
77
+ puts "Now, just type: omniscient clone #{custom_alias}"
78
+ exit
79
+
80
+ end
81
+
82
+ end
83
+ end
@@ -0,0 +1,10 @@
1
+ require 'configuration'
2
+ require 'ssh'
3
+
4
+ module Omniscient
5
+ class Connection
6
+ def initialize
7
+ @configuration = Omniscient::Configuration.new
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,33 @@
1
+ module Omniscient
2
+ class Scp
3
+
4
+ def initialize( config )
5
+ @attributes = config
6
+ end
7
+
8
+ def method_missing( name, *args, &block )
9
+ if args.empty? && block.nil?
10
+ if @attributes.has_key?(name.to_s)
11
+ @attributes[name.to_s]
12
+ elsif @attributes.has_key?(name.to_sym)
13
+ @attributes[name.to_sym]
14
+ else
15
+ nil
16
+ end
17
+ else
18
+ nil
19
+ end
20
+ end
21
+
22
+ def get_address
23
+ return false unless self.address
24
+ self.address
25
+ end
26
+
27
+ def connect( custom_message = '' )
28
+ command = "scp "+self.get_address.to_s
29
+ command.to_s
30
+ end
31
+
32
+ end
33
+ end
@@ -0,0 +1,34 @@
1
+ module Omniscient
2
+ class Ssh
3
+
4
+ def initialize( config )
5
+ @attributes = config
6
+ end
7
+
8
+ def method_missing( name, *args, &block )
9
+ if args.empty? && block.nil?
10
+ if @attributes.has_key?(name.to_s)
11
+ @attributes[name.to_s]
12
+ elsif @attributes.has_key?(name.to_sym)
13
+ @attributes[name.to_sym]
14
+ else
15
+ nil
16
+ end
17
+ else
18
+ nil
19
+ end
20
+ end
21
+
22
+ def get_address
23
+ return false unless self.address
24
+ self.address
25
+ end
26
+
27
+ def connect( custom_message = '' )
28
+ command = "ssh "+self.get_address.to_s
29
+ command << " '"+custom_message+"'" unless custom_message.empty?
30
+ command.to_s
31
+ end
32
+
33
+ end
34
+ end
@@ -0,0 +1,3 @@
1
+ module Omniscient
2
+ VERSION = "0.0.1"
3
+ end
@@ -0,0 +1,140 @@
1
+ module Shell
2
+
3
+ class Run
4
+
5
+ # all arguments passed
6
+ @argv
7
+
8
+ def initialize argv
9
+ @argv = argv
10
+
11
+ @options = Shell::Parser.get_options @argv
12
+ @command = Shell::Parser.get_command @argv
13
+ @arguments = Shell::Parser.get_arguments @argv
14
+ end
15
+
16
+ end
17
+
18
+ class Input
19
+
20
+ def self.text
21
+ begin
22
+ STDOUT.flush
23
+ STDIN.gets.strip
24
+ rescue
25
+ end
26
+ end
27
+
28
+ def self.yesno message
29
+ STDOUT.flush
30
+ has_result = false
31
+ while has_result == false
32
+ print message.strip + " "
33
+ input = STDIN.gets.strip
34
+
35
+ if input == "yes" or input == "y" then
36
+ final_input = "yes"
37
+ elsif input == "no" or input == "n" then
38
+ final_input = "no"
39
+ end
40
+
41
+ if ( final_input == "yes" or final_input == "no" )
42
+ has_result = true
43
+ end
44
+ end
45
+
46
+ if final_input == "yes"
47
+ result = true
48
+ else
49
+ result = false
50
+ end
51
+ result
52
+ end
53
+
54
+ end
55
+
56
+ class Parser
57
+
58
+ # defines the command of the application (e.g. 'push' in uplift push)
59
+ def self.get_command argv = []
60
+ command = String.new
61
+
62
+ argv.each {
63
+ |e|
64
+ e_length = e.length
65
+ if (e[0,2] != "--" and e[0,1] != "-") then
66
+ command = e
67
+ break
68
+ end
69
+ }
70
+
71
+ if command.empty? then
72
+ command = ""
73
+ end
74
+
75
+ command
76
+
77
+ end # get_command
78
+
79
+ # get only options in ARGV (arguments starting with _ or __)
80
+ def self.get_options argv
81
+ @options = Array.new
82
+
83
+ argv.each {
84
+ |e|
85
+ e_length = e.length
86
+ if e[0,2] == "--"
87
+ @options.push e[2,e_length]
88
+ elsif e[0,1] == "-"
89
+ @options.push e[1,e_length]
90
+ end
91
+ }
92
+ @options
93
+ end # get_options
94
+
95
+ def self.get_option_value option, argv = Array.new
96
+ next_item, option_value = false
97
+ argv.each { |e|
98
+ if next_item
99
+ option_value = e
100
+ break
101
+ end
102
+ e_length = e.length
103
+ if e[0,2] == "--"
104
+ next_item = true if e[2,e_length] == option
105
+ elsif e[0,1] == "-"
106
+ next_item = true if e[1,e_length] == option
107
+ end
108
+ }
109
+ option_value || ''
110
+ end
111
+
112
+ # get arguments. arguments are anything written besides the command and options.
113
+ # in 'push today --list', 'today' is the argument
114
+ def self.get_arguments argv
115
+ @arguments = Array.new
116
+ i = 0
117
+ argv.each {
118
+ |e|
119
+
120
+ i+= 1
121
+ next if i == 1
122
+
123
+ e_length = e.length
124
+ if e[0,2] != "--" and e[0,1] != "-"
125
+
126
+ @arguments.push e[0,e_length]
127
+ end
128
+
129
+ }
130
+ @arguments
131
+ end # get_options
132
+
133
+ def self.is_option option, argv = Array.new
134
+ argv_options = self.get_options argv
135
+ argv_options.include?(option)
136
+ end # is_option
137
+
138
+ end
139
+
140
+ end
@@ -0,0 +1,21 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+ require "omniscient/version"
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = "omniscient"
7
+ s.version = Omniscient::VERSION
8
+ s.platform = Gem::Platform::RUBY
9
+ s.authors = ["Alexandre de Oliveira"]
10
+ s.email = ["chavedomundo@gmail.com"]
11
+ s.homepage = "http://github.com/kurko/omniscient"
12
+ s.summary = %q{Manage DBs from your local machine.}
13
+ s.description = %q{Clone DBs from one machine to another.}
14
+
15
+ s.rubyforge_project = "omniscient"
16
+
17
+ s.files = `git ls-files`.split("\n")
18
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
19
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
20
+ s.require_paths = ["lib"]
21
+ end
@@ -0,0 +1,37 @@
1
+ require "test/unit"
2
+ require "omniscient"
3
+ require "adapters/mysql"
4
+
5
+ class MySQLTest < Test::Unit::TestCase
6
+
7
+ def tear_down
8
+ @mysql = nil
9
+ end
10
+
11
+ def setup
12
+ @mysql = Omniscient::Adapter::MySQL.new(
13
+ :database => 'omniscient',
14
+ :user => 'root',
15
+ :password => 'pw' )
16
+ end
17
+
18
+ def test_initialization
19
+ assert_equal 'omniscient', @mysql.database
20
+ assert_equal 'root', @mysql.user
21
+ end
22
+
23
+ def test_dump
24
+ assert_equal %Q{mysqldump -u root -ppw omniscient --single-transaction > .omni_dump.sql}, @mysql.dump()
25
+ end
26
+
27
+ def test_dump_a_specific_table
28
+ @mysql.attributes[:table] = 'mytable'
29
+ assert_equal %Q{mysqldump -u root -ppw omniscient mytable --single-transaction > .omni_dump.sql}, @mysql.dump()
30
+ end
31
+
32
+ def test_import
33
+ assert_equal %Q{mysql -u root -ppw omniscient < }+Omniscient::DUMP_LOCAL_PATH, @mysql.import()
34
+ end
35
+
36
+
37
+ end
@@ -0,0 +1,13 @@
1
+ require "test/unit"
2
+ require "omniscient"
3
+ require "command/clone"
4
+
5
+ class CloneTest < Test::Unit::TestCase
6
+ def setup
7
+
8
+ end
9
+
10
+ def test_start
11
+
12
+ end
13
+ end
@@ -0,0 +1,18 @@
1
+ require "test/unit"
2
+ require "omniscient"
3
+
4
+ class SshTest < Test::Unit::TestCase
5
+
6
+ def tear_down
7
+ @command = nil
8
+ end
9
+
10
+ def setup
11
+ @command = Omniscient::Command::Run.new
12
+ end
13
+
14
+ def test_initialization
15
+
16
+ end
17
+
18
+ end
@@ -0,0 +1,9 @@
1
+ require "test/unit"
2
+ require "omniscient"
3
+ require "connection"
4
+
5
+ class ConnectionTest < Test::Unit::TestCase
6
+ def setup
7
+ @conn = Omniscient::Connection.new
8
+ end
9
+ end
@@ -0,0 +1,37 @@
1
+ require "test/unit"
2
+ require "omniscient"
3
+ require "ssh"
4
+
5
+ class SshTest < Test::Unit::TestCase
6
+
7
+ def tear_down
8
+ @ssh = nil
9
+ end
10
+
11
+ def setup
12
+ @ssh = Omniscient::Ssh.new :address => 'user@localhost'
13
+ end
14
+
15
+ def test_initialization
16
+ assert_equal 'user@localhost', @ssh.address
17
+ end
18
+
19
+ def test_address
20
+ assert_equal 'user@localhost', @ssh.get_address()
21
+ end
22
+
23
+ def test_address_without_user
24
+ @ssh = Omniscient::Ssh.new :address => 'localhost'
25
+ assert_equal 'localhost', @ssh.get_address()
26
+ end
27
+
28
+ def test_address_with_port
29
+ @ssh = Omniscient::Ssh.new :address => 'user@localhost', :port => '22'
30
+ # TODO
31
+ end
32
+
33
+ def test_address_with_port
34
+ assert_equal %q{ssh user@localhost 'custom message'}, @ssh.connect('custom message')
35
+ end
36
+
37
+ end
metadata ADDED
@@ -0,0 +1,89 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: omniscient
3
+ version: !ruby/object:Gem::Version
4
+ prerelease: false
5
+ segments:
6
+ - 0
7
+ - 0
8
+ - 1
9
+ version: 0.0.1
10
+ platform: ruby
11
+ authors:
12
+ - Alexandre de Oliveira
13
+ autorequire:
14
+ bindir: bin
15
+ cert_chain: []
16
+
17
+ date: 2011-04-06 00:00:00 -03:00
18
+ default_executable:
19
+ dependencies: []
20
+
21
+ description: Clone DBs from one machine to another.
22
+ email:
23
+ - chavedomundo@gmail.com
24
+ executables:
25
+ - omniscient
26
+ extensions: []
27
+
28
+ extra_rdoc_files: []
29
+
30
+ files:
31
+ - .gitignore
32
+ - Gemfile
33
+ - README.markdown
34
+ - Rakefile
35
+ - bin/omniscient
36
+ - lib/omniscient.rb
37
+ - lib/omniscient/adapters/mysql.rb
38
+ - lib/omniscient/command.rb
39
+ - lib/omniscient/command/clone.rb
40
+ - lib/omniscient/configuration.rb
41
+ - lib/omniscient/connection.rb
42
+ - lib/omniscient/scp.rb
43
+ - lib/omniscient/ssh.rb
44
+ - lib/omniscient/version.rb
45
+ - lib/shell/shell.rb
46
+ - omniscient.gemspec
47
+ - test/lib/omniscient/adapters/test_mysql.rb
48
+ - test/lib/omniscient/command/test_clone.rb
49
+ - test/lib/omniscient/test_command.rb
50
+ - test/lib/omniscient/test_connection.rb
51
+ - test/lib/omniscient/test_ssh.rb
52
+ has_rdoc: true
53
+ homepage: http://github.com/kurko/omniscient
54
+ licenses: []
55
+
56
+ post_install_message:
57
+ rdoc_options: []
58
+
59
+ require_paths:
60
+ - lib
61
+ required_ruby_version: !ruby/object:Gem::Requirement
62
+ none: false
63
+ requirements:
64
+ - - ">="
65
+ - !ruby/object:Gem::Version
66
+ segments:
67
+ - 0
68
+ version: "0"
69
+ required_rubygems_version: !ruby/object:Gem::Requirement
70
+ none: false
71
+ requirements:
72
+ - - ">="
73
+ - !ruby/object:Gem::Version
74
+ segments:
75
+ - 0
76
+ version: "0"
77
+ requirements: []
78
+
79
+ rubyforge_project: omniscient
80
+ rubygems_version: 1.3.7
81
+ signing_key:
82
+ specification_version: 3
83
+ summary: Manage DBs from your local machine.
84
+ test_files:
85
+ - test/lib/omniscient/adapters/test_mysql.rb
86
+ - test/lib/omniscient/command/test_clone.rb
87
+ - test/lib/omniscient/test_command.rb
88
+ - test/lib/omniscient/test_connection.rb
89
+ - test/lib/omniscient/test_ssh.rb