dbgeni 0.10.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (46) hide show
  1. checksums.yaml +7 -0
  2. data/Rakefile +29 -0
  3. data/bin/dbgeni +2 -0
  4. data/lib/dbgeni/base.rb +146 -0
  5. data/lib/dbgeni/base_code.rb +143 -0
  6. data/lib/dbgeni/blank_slate.rb +24 -0
  7. data/lib/dbgeni/cli.rb +96 -0
  8. data/lib/dbgeni/code.rb +235 -0
  9. data/lib/dbgeni/code_list.rb +60 -0
  10. data/lib/dbgeni/commands/code.rb +151 -0
  11. data/lib/dbgeni/commands/commands.rb +41 -0
  12. data/lib/dbgeni/commands/config.rb +36 -0
  13. data/lib/dbgeni/commands/dmls.rb +244 -0
  14. data/lib/dbgeni/commands/generate.rb +257 -0
  15. data/lib/dbgeni/commands/initialize.rb +41 -0
  16. data/lib/dbgeni/commands/migrations.rb +243 -0
  17. data/lib/dbgeni/commands/milestones.rb +52 -0
  18. data/lib/dbgeni/commands/new.rb +178 -0
  19. data/lib/dbgeni/config.rb +325 -0
  20. data/lib/dbgeni/connectors/connector.rb +59 -0
  21. data/lib/dbgeni/connectors/mysql.rb +146 -0
  22. data/lib/dbgeni/connectors/oracle.rb +149 -0
  23. data/lib/dbgeni/connectors/sqlite.rb +166 -0
  24. data/lib/dbgeni/connectors/sybase.rb +97 -0
  25. data/lib/dbgeni/dml_cli.rb +35 -0
  26. data/lib/dbgeni/environment.rb +161 -0
  27. data/lib/dbgeni/exceptions/exception.rb +69 -0
  28. data/lib/dbgeni/file_converter.rb +44 -0
  29. data/lib/dbgeni/initializers/initializer.rb +44 -0
  30. data/lib/dbgeni/initializers/mysql.rb +36 -0
  31. data/lib/dbgeni/initializers/oracle.rb +38 -0
  32. data/lib/dbgeni/initializers/sqlite.rb +33 -0
  33. data/lib/dbgeni/initializers/sybase.rb +34 -0
  34. data/lib/dbgeni/logger.rb +60 -0
  35. data/lib/dbgeni/migration.rb +302 -0
  36. data/lib/dbgeni/migration_cli.rb +204 -0
  37. data/lib/dbgeni/migration_list.rb +91 -0
  38. data/lib/dbgeni/migrators/migrator.rb +40 -0
  39. data/lib/dbgeni/migrators/migrator_interface.rb +51 -0
  40. data/lib/dbgeni/migrators/mysql.rb +82 -0
  41. data/lib/dbgeni/migrators/oracle.rb +211 -0
  42. data/lib/dbgeni/migrators/sqlite.rb +90 -0
  43. data/lib/dbgeni/migrators/sybase.rb +118 -0
  44. data/lib/dbgeni/plugin.rb +92 -0
  45. data/lib/dbgeni.rb +52 -0
  46. metadata +87 -0
@@ -0,0 +1,90 @@
1
+ module DBGeni
2
+ module Migrator
3
+
4
+ class Sqlite < DBGeni::Migrator::MigratorInterface
5
+
6
+ def initialize(config, connection)
7
+ super(config, connection)
8
+ end
9
+
10
+ def migration_errors
11
+ ''
12
+ end
13
+
14
+ # def apply(migration, force=nil)
15
+ # end
16
+
17
+ # def rollback(migration, force=nil)
18
+ # end
19
+
20
+ # def verify(migration)
21
+ # end
22
+
23
+ def compile(code, force=false)
24
+ raise DBGeni::NotImplemented
25
+ end
26
+
27
+ # def remove(code)
28
+ # end
29
+
30
+ # def code_errors
31
+ # end
32
+
33
+ private
34
+
35
+ def run_in_client(file, force=nil)
36
+ null_device = '/dev/null'
37
+ if Kernel.is_windows?
38
+ null_device = 'NUL:'
39
+ end
40
+
41
+ @logfile = "#{@log_dir}/#{File.basename(file)}"
42
+ IO.popen("sqlite3 #{@connection.database} > #{@logfile} 2>&1", "w") do |p|
43
+ unless force
44
+ p.puts ".bail on"
45
+ end
46
+ p.puts ".echo on"
47
+ p.puts ".read #{file}"
48
+ p.puts ".quit"
49
+ end
50
+ # On OSX sqlite exits with 0 even when the sql script contains errors.
51
+ # On windows when there are errors it exits with 1.
52
+ #
53
+ # The only way to see if the script contained errors consistently is
54
+ # to grep the logfile for lines starting SQL error near line
55
+ # No point in checking if force is on as the errors don't matter anyway.
56
+ has_errors = false
57
+ unless force
58
+ # For empty migrations, sometimes no logfile?
59
+ if File.exists? @logfile
60
+ File.open(@logfile, 'r').each do |l|
61
+ if l =~ /^SQL error near line/
62
+ has_errors = true
63
+ break
64
+ end
65
+ end
66
+ end
67
+ end
68
+ # When the system call ends, ruby sets $? with the exit status. A
69
+ # good exit status is 0 (zero) anything else means it went wrong
70
+ # If $? is anything but zero, raise an exception.
71
+ if $? != 0 or has_errors
72
+ # if there were errors in the migration, SQLITE seems to set a non-zero
73
+ # exit status on **windows only**, depite running the migration to completion.
74
+ # So if the exit status is non-zero AND force is NOT true, raise, otherwise don't.
75
+ unless force
76
+ raise DBGeni::MigrationContainsErrors
77
+ end
78
+ end
79
+ end
80
+
81
+ def ensure_executable_exists
82
+ unless Kernel.executable_exists?('sqlite3')
83
+ raise DBGeni::DBCLINotOnPath
84
+ end
85
+ end
86
+
87
+ end
88
+ end
89
+
90
+ end
@@ -0,0 +1,118 @@
1
+ module DBGeni
2
+ module Migrator
3
+
4
+ class Sybase < DBGeni::Migrator::MigratorInterface
5
+
6
+ def initialize(config, connection)
7
+ super(config, connection)
8
+ end
9
+
10
+ # Defined in super ...
11
+ # def apply(migration, force=nil)
12
+ # end
13
+
14
+ # def rollback(migration, force=nil)
15
+ # end
16
+
17
+ def migration_errors
18
+ error = ''
19
+ # The first error is the one to report - with sybase isql doesn't stop on errors
20
+ # The error lines tend to look like:
21
+ # Msg 156, Level 15, State 2:
22
+ # Server 'WW637L18714A', Line 2:
23
+ # Incorrect syntax near the keyword 'table'.
24
+ begin
25
+ fh = File.open(@logfile, 'r')
26
+ # search for a line starting Msg or Error and then grab the next 2 lines to make up the error.
27
+ while (l = fh.readline)
28
+ if l =~ /^(Msg|Error)\s\d+/
29
+ error = l
30
+ break
31
+ end
32
+ end
33
+ unless error == ''
34
+ # if an error was found, add the next two lines to the error message
35
+ error << fh.readline
36
+ error << fh.readline
37
+ end
38
+ rescue ::EOFError
39
+ # reached the end of file before a full error message was found ...
40
+ # Just catch and move on ...
41
+ ensure
42
+ fh.close if fh
43
+ end
44
+ error
45
+ end
46
+
47
+ # def verify(migration)
48
+ # end
49
+
50
+ def remove(code, force=false)
51
+ begin
52
+ @connection.execute(drop_command(code))
53
+ rescue Exception => e
54
+ unless e.to_s =~ /Cannot drop the .*(procedure|function|trigger).+exist in the system catalogs/i
55
+ raise DBGeni::CodeRemoveFailed, e.to_s
56
+ end
57
+ end
58
+ end
59
+
60
+ def code_errors
61
+ # In sybase the code errors are just the same as migration errors
62
+ errors = migration_errors
63
+ if errors == ''
64
+ errors = nil
65
+ end
66
+ errors
67
+ end
68
+
69
+ private
70
+
71
+ def run_in_client(file, force, is_proc=false)
72
+ @logfile = "#{@log_dir}/#{File.basename(file)}"
73
+
74
+ z = @config.env
75
+ # -e echos input
76
+ # -w200 - sets line width to 250 from the default of 80
77
+ response = system("isql -U#{z.username} -P#{z.password} -S#{z.sybase_service} -D#{z.database} -e -w 200 -i#{file} -o#{logfile}")
78
+
79
+ has_errors = false
80
+ unless force
81
+ # For empty migrations, sometimes no logfile?
82
+ if File.exists? @logfile
83
+ File.open(@logfile, 'r').each do |l|
84
+ if l =~ /^(Msg|Error)\s\d+/
85
+ has_errors = true
86
+ break
87
+ end
88
+ end
89
+ end
90
+ end
91
+
92
+ if has_errors or !response
93
+ unless force
94
+ raise DBGeni::MigrationContainsErrors
95
+ end
96
+ end
97
+ end
98
+
99
+ def ensure_executable_exists
100
+ unless Kernel.executable_exists?('isql')
101
+ raise DBGeni::DBCLINotOnPath
102
+ end
103
+ end
104
+
105
+ def drop_command(code)
106
+ case code.type
107
+ when DBGeni::Code::TRIGGER
108
+ "drop trigger #{code.name.downcase}"
109
+ when DBGeni::Code::FUNCTION
110
+ "drop function #{code.name.downcase}"
111
+ when DBGeni::Code::PROCEDURE
112
+ "drop procedure #{code.name.downcase}"
113
+ end
114
+ end
115
+
116
+ end
117
+ end
118
+ end
@@ -0,0 +1,92 @@
1
+ module DBGeni
2
+ class Plugin
3
+ class << self
4
+ attr_reader :hooks
5
+
6
+ def install_plugin(hook, klass)
7
+ unless @hooks.has_key? hook
8
+ raise DBGeni::InvalidHook
9
+ end
10
+ @hooks[hook].push klass
11
+ end
12
+
13
+ def reset
14
+ @hooks.keys.each do |k|
15
+ @hooks[k] = Array.new
16
+ end
17
+ end
18
+
19
+ end
20
+
21
+ @hooks = {
22
+ :before_migration_up => [],
23
+ :after_migration_up => [],
24
+ :before_migration_down => [],
25
+ :after_migration_down => [],
26
+ :before_dml_up => [],
27
+ :after_dml_up => [],
28
+ :before_dml_down => [],
29
+ :after_dml_down => [],
30
+ :before_code_apply => [],
31
+ :after_code_apply => [],
32
+ :before_code_remove => [],
33
+ :after_code_remove => [],
34
+ :before_running_migrations => [],
35
+ :after_running_migrations => [],
36
+ :before_running_dmls => [],
37
+ :after_running_dmls => [],
38
+ :before_modifying_code => [],
39
+ :after_modifying_code => []
40
+ }
41
+
42
+
43
+ def initialize
44
+ end
45
+
46
+ def load_plugins(path)
47
+ begin
48
+ files = Dir.entries(path).grep(/\.rb$/).sort
49
+ rescue Errno::ENOENT, Errno::EACCES => e
50
+ raise DBGeni::PluginDirectoryNotAccessible, e.to_s
51
+ end
52
+ files.each do |f|
53
+ load_plugin File.join(path, f)
54
+ end
55
+ end
56
+
57
+ def load_plugin(filename)
58
+ require filename
59
+ end
60
+
61
+ def run_plugins(hook, attrs)
62
+ klasses = self.class.hooks[hook]
63
+ unless klasses.is_a? Array
64
+ raise DBGeni::InvalidHook, hook
65
+ end
66
+
67
+ klasses.each do |k|
68
+ run_plugin k, hook, attrs
69
+ end
70
+ end
71
+
72
+ def run_plugin(klass, hook, attrs)
73
+ instance = klass.new
74
+ unless instance.respond_to? :run
75
+ raise DBGeni::PluginDoesNotRespondToRun
76
+ end
77
+ instance.run(hook, attrs)
78
+ end
79
+
80
+ end
81
+ end
82
+
83
+ class Class
84
+ DBGeni::Plugin.hooks.keys.each do |k|
85
+ self.class_eval <<-end_eval
86
+ def #{k.to_s}
87
+ DBGeni::Plugin.install_plugin(:#{k.to_s}, self)
88
+ end
89
+ end_eval
90
+ end
91
+ end
92
+
data/lib/dbgeni.rb ADDED
@@ -0,0 +1,52 @@
1
+ require 'rbconfig'
2
+ require 'digest/sha1'
3
+
4
+ module Kernel
5
+
6
+ def self.is_windows?
7
+ # Ruby 1.9.3 warns if you use Config (instead of RbConfig) while older Ruby
8
+ # doesn't have RbConfig, only Config :-/
9
+ conf = Object.const_get(defined?(RbConfig) ? :RbConfig : :Config)::CONFIG
10
+ conf['host_os'] =~ /mswin|mingw/
11
+ end
12
+
13
+ def suppress_warnings
14
+ original_verbosity = $VERBOSE
15
+ $VERBOSE = nil
16
+ result = yield
17
+ $VERBOSE = original_verbosity
18
+ return result
19
+ end
20
+
21
+ def self.executable_exists?(cmd)
22
+ exts = ENV['PATHEXT'] ? ENV['PATHEXT'].split(';') : ['']
23
+ ENV['PATH'].split(File::PATH_SEPARATOR).each do |path|
24
+ exts.each { |ext|
25
+ exe = "#{path}/#{cmd}#{ext}"
26
+ return exe if File.executable? exe
27
+ }
28
+ end
29
+ return nil
30
+ end
31
+
32
+ end
33
+
34
+ if RUBY_PLATFORM == 'java'
35
+ require 'rubygems'
36
+ require 'java'
37
+
38
+ conf = Object.const_get(defined?(RbConfig) ? :RbConfig : :Config)::CONFIG
39
+ if conf['ruby_version'] =~ /1\.8/
40
+ raise "DBGeni requires the --1.9 switch to be passed to jruby (or set env variable JRUBY_OPTS=--1.9)"
41
+ end
42
+
43
+ module JavaLang
44
+ include_package "java.lang"
45
+ end
46
+
47
+ module JavaSql
48
+ include_package 'java.sql'
49
+ end
50
+ end
51
+
52
+ require 'dbgeni/base'
metadata ADDED
@@ -0,0 +1,87 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: dbgeni
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.10.0
5
+ platform: ruby
6
+ authors:
7
+ - Stephen O'Donnell
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2014-03-11 00:00:00.000000000 Z
12
+ dependencies: []
13
+ description: Generic installer to manage database migrations for various databases
14
+ email: stephen@betteratoracle.com
15
+ executables:
16
+ - dbgeni
17
+ extensions: []
18
+ extra_rdoc_files: []
19
+ files:
20
+ - Rakefile
21
+ - bin/dbgeni
22
+ - lib/dbgeni.rb
23
+ - lib/dbgeni/base.rb
24
+ - lib/dbgeni/base_code.rb
25
+ - lib/dbgeni/blank_slate.rb
26
+ - lib/dbgeni/cli.rb
27
+ - lib/dbgeni/code.rb
28
+ - lib/dbgeni/code_list.rb
29
+ - lib/dbgeni/commands/code.rb
30
+ - lib/dbgeni/commands/commands.rb
31
+ - lib/dbgeni/commands/config.rb
32
+ - lib/dbgeni/commands/dmls.rb
33
+ - lib/dbgeni/commands/generate.rb
34
+ - lib/dbgeni/commands/initialize.rb
35
+ - lib/dbgeni/commands/migrations.rb
36
+ - lib/dbgeni/commands/milestones.rb
37
+ - lib/dbgeni/commands/new.rb
38
+ - lib/dbgeni/config.rb
39
+ - lib/dbgeni/connectors/connector.rb
40
+ - lib/dbgeni/connectors/mysql.rb
41
+ - lib/dbgeni/connectors/oracle.rb
42
+ - lib/dbgeni/connectors/sqlite.rb
43
+ - lib/dbgeni/connectors/sybase.rb
44
+ - lib/dbgeni/dml_cli.rb
45
+ - lib/dbgeni/environment.rb
46
+ - lib/dbgeni/exceptions/exception.rb
47
+ - lib/dbgeni/file_converter.rb
48
+ - lib/dbgeni/initializers/initializer.rb
49
+ - lib/dbgeni/initializers/mysql.rb
50
+ - lib/dbgeni/initializers/oracle.rb
51
+ - lib/dbgeni/initializers/sqlite.rb
52
+ - lib/dbgeni/initializers/sybase.rb
53
+ - lib/dbgeni/logger.rb
54
+ - lib/dbgeni/migration.rb
55
+ - lib/dbgeni/migration_cli.rb
56
+ - lib/dbgeni/migration_list.rb
57
+ - lib/dbgeni/migrators/migrator.rb
58
+ - lib/dbgeni/migrators/migrator_interface.rb
59
+ - lib/dbgeni/migrators/mysql.rb
60
+ - lib/dbgeni/migrators/oracle.rb
61
+ - lib/dbgeni/migrators/sqlite.rb
62
+ - lib/dbgeni/migrators/sybase.rb
63
+ - lib/dbgeni/plugin.rb
64
+ homepage: http://dbgeni.com
65
+ licenses: []
66
+ metadata: {}
67
+ post_install_message:
68
+ rdoc_options: []
69
+ require_paths:
70
+ - lib
71
+ required_ruby_version: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ required_rubygems_version: !ruby/object:Gem::Requirement
77
+ requirements:
78
+ - - ">="
79
+ - !ruby/object:Gem::Version
80
+ version: '0'
81
+ requirements: []
82
+ rubyforge_project:
83
+ rubygems_version: 2.2.0
84
+ signing_key:
85
+ specification_version: 4
86
+ summary: A generic database installer
87
+ test_files: []