orasaurus 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (41) hide show
  1. data/.gitignore +4 -0
  2. data/Gemfile +4 -0
  3. data/README.textile +7 -0
  4. data/Rakefile +1 -0
  5. data/bin/orasaurus +4 -0
  6. data/lib/orasaurus/sql_script_builder.rb +162 -0
  7. data/lib/orasaurus/version.rb +3 -0
  8. data/lib/orasaurus.rb +12 -0
  9. data/notes/build_table_build_script.rb +207 -0
  10. data/notes/db_migrator.rb +115 -0
  11. data/notes/file_dependencies.rb +65 -0
  12. data/notes/main_db.rb +130 -0
  13. data/notes/rakefile.rb +375 -0
  14. data/notes/stractor.rb +41 -0
  15. data/notes/try_to_compile.rb +28 -0
  16. data/orasaurus.gemspec +26 -0
  17. data/spec/orasaurus_spec.rb +12 -0
  18. data/spec/spec_helper.rb +8 -0
  19. data/test/db/Notes/Packages/build.sql +35 -0
  20. data/test/db/Notes/Packages/pkg_note_comments.pkg +164 -0
  21. data/test/db/Notes/Packages/pkg_note_tags.pkg +146 -0
  22. data/test/db/Notes/Packages/pkg_notebooks.pkg +135 -0
  23. data/test/db/Notes/Packages/pkg_notes.pkg +418 -0
  24. data/test/db/Notes/Packages/teardown.sql +36 -0
  25. data/test/db/Notes/Sequences/build.sql +35 -0
  26. data/test/db/Notes/Sequences/note_comments_seq.sql +1 -0
  27. data/test/db/Notes/Sequences/note_tags_seq.sql +1 -0
  28. data/test/db/Notes/Sequences/notebooks_seq.sql +1 -0
  29. data/test/db/Notes/Sequences/notes_seq.sql +1 -0
  30. data/test/db/Notes/Sequences/teardown.sql +36 -0
  31. data/test/db/Notes/Tables/build.sql +35 -0
  32. data/test/db/Notes/Tables/note_comments.sql +27 -0
  33. data/test/db/Notes/Tables/note_tags.sql +25 -0
  34. data/test/db/Notes/Tables/notebooks.sql +26 -0
  35. data/test/db/Notes/Tables/notes.sql +30 -0
  36. data/test/db/Notes/Tables/teardown.sql +36 -0
  37. data/test/db/Rakefile +75 -0
  38. data/test/db/build.sql +26 -0
  39. data/test/db/create_test_user.sql +3 -0
  40. data/test/db/teardown.sql +36 -0
  41. metadata +119 -0
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 orasaurus.gemspec
4
+ gemspec
data/README.textile ADDED
@@ -0,0 +1,7 @@
1
+ h1. Orasaurus
2
+
3
+ Tools for building Oracle databases.
4
+
5
+ Development is just getting started.
6
+
7
+ Check back for more progress and an initial release soon.
data/Rakefile ADDED
@@ -0,0 +1 @@
1
+ require "bundler/gem_tasks"
data/bin/orasaurus ADDED
@@ -0,0 +1,4 @@
1
+ #!/usr/bin/env ruby
2
+ require File.dirname(__FILE__) + '/../lib/orasaurus.rb'
3
+
4
+ Orasaurus(ARGV)
@@ -0,0 +1,162 @@
1
+ require 'find'
2
+ require 'erb'
3
+
4
+ module Orasaurus
5
+
6
+ class ScriptBuilder
7
+
8
+ def initialize( base_directory )
9
+
10
+ @base_directory = base_directory
11
+ @ignore_directories = %w( )
12
+ @ignore_filenames = %w( build.sql teardown.sql build.log teardown.log )
13
+ @buildable_file_extensions = %w( .pkg .pks .pkb .sql .trg )
14
+ @build_directories = Array.new
15
+ @buildable_items = Array.new
16
+
17
+ @build_directories = fill_build_directories
18
+
19
+ end
20
+
21
+ def fill_build_directories
22
+ return_array = Array.new
23
+ Find.find(@base_directory) do |f|
24
+ if File.directory?( f )
25
+ if not @ignore_directories.include?( f.split("/").pop )
26
+ return_array.push( f )
27
+ else
28
+ puts "pruning " + f
29
+ Find.prune
30
+ end
31
+ end
32
+ end
33
+ return return_array
34
+ end
35
+
36
+ def build_all_scripts(build_file_name, teardown_file_name)
37
+ @build_directories.each do |d|
38
+ @buildable_items = get_buildable_items(d)
39
+ if @buildable_items.length >0 then
40
+ generate_build_script( d + "/" + build_file_name )
41
+ generate_teardown_script( d + "/" + teardown_file_name ) unless d == "DBSeeds"
42
+ #puts "completed working with " + d
43
+ else
44
+ #puts "directory ignored: " + d
45
+ end
46
+ end
47
+ end
48
+
49
+ def get_buildable_items(dir)
50
+ buildable_items = Array.new
51
+ #puts Dir.glob(dir + "/*.*" )
52
+ if dir.match( /Packages/ )
53
+ search_list = Dir.glob( dir + "/*.pks" ) + Dir.glob( dir + "/*.pkb" ) + Dir.glob( dir + "/*.pkg" )
54
+ else
55
+ search_list = Dir.glob(dir + "/*.*" )
56
+ end
57
+ search_list.each do |f|
58
+ if not File.directory?( f ) \
59
+ and not @ignore_filenames.include?(File.basename( f )) \
60
+ and @buildable_file_extensions.include?(File.extname( f )) \
61
+ then
62
+ buildable_items.push(File.basename( f ))
63
+ end
64
+ end
65
+ return buildable_items
66
+ end
67
+
68
+ def generate_build_script( output_file_name )
69
+ buildables = @buildable_items
70
+ #puts @buildable_items.inspect
71
+ @build_template = %q{
72
+ SET SERVEROUTPUT ON
73
+ SET DEFINE OFF
74
+ SPOOL build.log
75
+
76
+ PROMPT
77
+ PROMPT *****************************GETTING STARTED************************
78
+ PROMPT
79
+ /
80
+ BEGIN DBMS_OUTPUT.PUT_LINE( 'BEGIN TIME: '||TO_CHAR( SYSDATE, 'MM/DD/YYYY HH:MI:SS' ) ); END;
81
+ /
82
+
83
+ <% buildables.each do |item| %>
84
+ PROMPT ***** <%= item %> *****
85
+ @<%= item %>;
86
+ SHOW ERRORS
87
+ <% end %>
88
+
89
+ BEGIN DBMS_OUTPUT.PUT_LINE( 'END TIME: '||TO_CHAR( SYSDATE, 'MM/DD/YYYY HH:MI:SS' ) ); END;
90
+ /
91
+ PROMPT
92
+ PROMPT *******************************FINISHED*******************************
93
+ PROMPT
94
+
95
+
96
+ EXIT
97
+ /
98
+ }
99
+
100
+
101
+ script_contents = ERB.new( @build_template, nil, ">" ).result(binding)
102
+ script_file = File.new( output_file_name, "w" )
103
+ script_file.print( script_contents )
104
+
105
+ end
106
+
107
+ def generate_teardown_script( output_file_name )
108
+
109
+ @teardown_template = %q{
110
+ SET SERVEROUTPUT ON
111
+ SET DEFINE OFF
112
+ SPOOL teardown.log
113
+
114
+ DECLARE
115
+ CURSOR cur_drop_list
116
+ IS
117
+ SELECT *
118
+ FROM USER_OBJECTS
119
+ WHERE OBJECT_NAME IN ( <%=@sql_in_clause%> )
120
+ AND OBJECT_TYPE != 'PACKAGE BODY';
121
+ x BOOLEAN := FALSE;
122
+ BEGIN
123
+ DBMS_OUTPUT.PUT_LINE( 'starting work' );
124
+ FOR i IN cur_drop_list LOOP
125
+ x := TRUE;
126
+ BEGIN
127
+ EXECUTE IMMEDIATE 'DROP '||i.object_type||' '||i.object_name||' CASCADE CONSTRAINTS';
128
+ DBMS_OUTPUT.PUT_LINE( 'DROPPED '||i.object_name );
129
+ EXCEPTION
130
+ WHEN OTHERS THEN
131
+ DBMS_OUTPUT.PUT_LINE( 'WHILE DROPPING '||i.object_type||' '||i.object_name );
132
+ DBMS_OUTPUT.PUT_LINE( SUBSTR( SQLERRM, 1, 255 ) );
133
+ END;
134
+ END LOOP;
135
+ IF NOT x THEN
136
+ DBMS_OUTPUT.PUT_LINE( 'NOTHING FOUND TO DROP' );
137
+ END IF;
138
+ DBMS_OUTPUT.PUT_LINE( 'completed successfully' );
139
+ END;
140
+ /
141
+
142
+ EXIT
143
+ /
144
+ }
145
+
146
+ @sql_in_clause = ""
147
+ @buildable_items.each do |i|
148
+ if i == @buildable_items.first then
149
+ @sql_in_clause.concat( "'" + i.chomp( File.extname( i ) ).upcase + "'" )
150
+ else
151
+ @sql_in_clause.concat( ", '" + i.chomp( File.extname( i ) ).upcase + "'" )
152
+ end
153
+ end
154
+
155
+ script_contents = ERB.new( @teardown_template, nil, ">" ).result(binding)
156
+ script_file = File.new( output_file_name, "w" )
157
+ script_file.print( script_contents )
158
+ end
159
+
160
+ end
161
+
162
+ end
@@ -0,0 +1,3 @@
1
+ module Orasaurus
2
+ VERSION = "0.0.1"
3
+ end
data/lib/orasaurus.rb ADDED
@@ -0,0 +1,12 @@
1
+
2
+ module Orasaurus
3
+
4
+ def self.sync_build_scripts(*args)
5
+ args = args
6
+ p args
7
+ end
8
+
9
+
10
+ end
11
+
12
+ require 'orasaurus/sql_script_builder'
@@ -0,0 +1,207 @@
1
+ require 'oci8'
2
+ require 'erb'
3
+
4
+ class TableScriptBuilder
5
+
6
+ def initialize( db_user, db_password, db_name, output_path )
7
+
8
+ @db_user = db_user
9
+ @db_password = db_password
10
+ @db_name = db_name
11
+ @output_path = output_path
12
+
13
+ puts "producing raw table list"
14
+ @raw_table_list = get_table_list
15
+ puts "raw table list count: " + @raw_table_list.length.to_s
16
+ #puts @raw_table_list
17
+
18
+ puts "producing ordered table list"
19
+ @ordered_table_list = produce_ordered_list
20
+ puts "ordered_table_list count: " + @ordered_table_list.length.to_s
21
+ #puts @ordered_table_list
22
+
23
+ puts "producing build script"
24
+ @build_script = make_build_script
25
+
26
+ puts "producing teardown script"
27
+ @teardown_script = make_teardown_script
28
+
29
+ end
30
+
31
+ def get_table_list
32
+
33
+ table_qry = %q{
34
+ SELECT table_name
35
+ FROM user_tables
36
+ WHERE ( table_name LIKE 'FNS%' OR table_name LIKE 'FDR%' )
37
+ }
38
+
39
+ table_list = Array.new
40
+
41
+ db_connection = OCI8.new( @db_user, @db_password, @db_name )
42
+
43
+ db_connection.exec( table_qry ) do |row|
44
+ table_list.push( row.first )
45
+ end
46
+
47
+ db_connection.logoff
48
+
49
+ return table_list
50
+
51
+ end
52
+
53
+ def get_dependency_list(table_name)
54
+
55
+ dependency_qry = %q{ select UNIQUE b.table_name dependent_table
56
+ from user_constraints a
57
+ join user_constraints b
58
+ on a.r_constraint_name = b.constraint_name
59
+ where a.constraint_type = 'R'
60
+ and ( a.table_name LIKE 'FNS%'
61
+ or a.table_name LIKE 'FDR%' )
62
+ and a.table_name = :table_name
63
+ order by b.table_name
64
+ }
65
+
66
+ dependency_list = Array.new
67
+
68
+ db_connection = OCI8.new(@db_user, @db_password, @db_name)
69
+
70
+ db_connection.exec(dependency_qry, table_name) do |row|
71
+ dependency_list.push(row.first)
72
+ end
73
+
74
+ db_connection.logoff
75
+
76
+ return dependency_list
77
+
78
+ end
79
+
80
+ def produce_ordered_list
81
+
82
+ ordered_list = Array.new
83
+ done_collecting = false
84
+ loop_idx = 0
85
+
86
+ while not done_collecting
87
+
88
+ loop_idx += 1
89
+
90
+ @raw_table_list.each{ |table|
91
+
92
+ if not ordered_list.include?(table) then
93
+
94
+ dependencies = get_dependency_list(table).sort
95
+
96
+ if dependencies.length == 0 then
97
+ ordered_list.push( table )
98
+ else
99
+ #this line of code is checking to see if all of the dependencies
100
+ # for the table we are analyzing are already int the ordered_list
101
+ matches = ordered_list.select{ |i| dependencies.include?(i) }
102
+ matches = matches.sort
103
+ if matches.eql?(dependencies)
104
+ ordered_list.push( table )
105
+ end
106
+ end
107
+ end
108
+
109
+ }
110
+
111
+ if ordered_list.sort.eql?(@raw_table_list.sort) then
112
+ done_collecting = true
113
+ puts "done colecting dependency matches. all tables have been collected and matched."
114
+ end
115
+
116
+ if loop_idx > 10
117
+ done_collecting = true
118
+ puts "giving up on finishing collecting"
119
+ puts "difference (missing ones): "
120
+ puts @raw_table_list - ordered_list
121
+ end
122
+
123
+ end
124
+
125
+ return ordered_list
126
+
127
+ end
128
+
129
+ def make_build_script
130
+ build_template = %q{
131
+ SET SERVEROUTPUT ON
132
+ SET DEFINE OFF
133
+ SPOOL build.log
134
+
135
+ PROMPT
136
+ PROMPT *****************************GETTING STARTED************************
137
+ PROMPT
138
+ /
139
+ BEGIN DBMS_OUTPUT.PUT_LINE( 'BEGIN TIME: '||TO_CHAR( SYSDATE, 'MM/DD/YYYY HH:MI:SS' ) ); END;
140
+ /
141
+
142
+ <% @ordered_table_list.each do |item| %>
143
+ PROMPT
144
+ PROMPT ***** <%= item %> ******
145
+ PROMPT
146
+ @<%= item %>;
147
+
148
+ <% end %>
149
+
150
+ BEGIN DBMS_OUTPUT.PUT_LINE( 'END TIME: '||TO_CHAR( SYSDATE, 'MM/DD/YYYY HH:MI:SS' ) ); END;
151
+ /
152
+ PROMPT
153
+ PROMPT *******************************FINISHED*******************************
154
+ PROMPT
155
+
156
+
157
+ EXIT
158
+ /
159
+ }
160
+
161
+
162
+ script_contents = ERB.new( build_template, nil, ">" ).result(binding)
163
+ script_file = File.new( @output_path + "build.sql", "w" )
164
+ script_file.print( script_contents )
165
+
166
+ end
167
+
168
+ def make_teardown_script
169
+
170
+ teardown_template = %q{
171
+ SET SERVEROUTPUT ON
172
+ SET DEFINE OFF
173
+ SPOOL teardown.log
174
+
175
+ PROMPT
176
+ PROMPT *****************************GETTING STARTED************************
177
+ PROMPT
178
+ /
179
+ BEGIN DBMS_OUTPUT.PUT_LINE( 'BEGIN TIME: '||TO_CHAR( SYSDATE, 'MM/DD/YYYY HH:MI:SS' ) ); END;
180
+ /
181
+
182
+ <% @ordered_table_list.reverse.each do |item| %>
183
+ PROMPT
184
+ PROMPT <%= item + "\n" %>
185
+ PROMPT
186
+ DROP TABLE <%= item %> CASCADE CONSTRAINTS;
187
+ <% end %>
188
+
189
+ BEGIN DBMS_OUTPUT.PUT_LINE( 'END TIME: '||TO_CHAR( SYSDATE, 'MM/DD/YYYY HH:MI:SS' ) ); END;
190
+ /
191
+ PROMPT
192
+ PROMPT *******************************FINISHED*******************************
193
+ PROMPT
194
+
195
+
196
+ EXIT
197
+ /
198
+ }
199
+
200
+
201
+ script_contents = ERB.new( teardown_template, nil, ">" ).result(binding)
202
+ script_file = File.new( @output_path + "teardown.sql", "w" )
203
+ script_file.print( script_contents )
204
+
205
+ end
206
+
207
+ end
@@ -0,0 +1,115 @@
1
+ require "find"
2
+ require "fileutils"
3
+ require "highline/import"
4
+ require "oci8"
5
+
6
+ class DbMigrator
7
+
8
+ @migration_directory
9
+ @current_db_version
10
+ @db_name
11
+ @db_user
12
+ @db_user_password
13
+
14
+ def initialize( migration_directory, db_name, db_user, db_user_password )
15
+ @migration_directory = migration_directory
16
+ @db_name = db_name
17
+ @db_user = db_user
18
+ @db_user_password = db_user_password
19
+ puts "Initializing database migrator"
20
+ @current_db_version = get_current_db_version
21
+ end
22
+
23
+ def get_current_db_version
24
+ current_version = 0
25
+ begin
26
+ conn = OCI8.new( $db_user, $db_user_password, $db_name )
27
+ cursor = conn.exec( 'select value from tbparameters where system = \'FNS\' AND key = \'DB_VERSION\'' )
28
+ current_version = cursor.fetch.first.to_i
29
+ conn.logoff
30
+ rescue
31
+ puts "Error getting current db version from the database: #{ $! }"
32
+ continue = ask( "The database version cannot be retrieved from the database. Would you like to continue?" ){ |q| q.echo = true }
33
+ #if response begins with y
34
+ if continue =~ /y/i then
35
+ current_version = ask( "What is the current version number of the database (migrations that are greater than this number will be run)?", Integer ){ |q| q.echo = true }
36
+ else
37
+ puts "Exiting immediately. No database migrations will be run"
38
+ exit
39
+ end
40
+ end
41
+ return current_version
42
+ end
43
+
44
+ def set_db_version( version_no )
45
+ begin
46
+ conn = OCI8.new( $db_user, $db_user_password, $db_name )
47
+ rows_updated = conn.exec( 'update tbparameters set value = :version_no where system = \'FNS\' AND key = \'DB_VERSION\'', version_no )
48
+ if rows_updated == 1
49
+ conn.commit
50
+ else
51
+ conn.rollback
52
+ "#{ rows_updated } when 1 row was expected."
53
+ end
54
+ conn.logoff
55
+ puts "new db_version set #{ version_no }"
56
+ rescue
57
+ puts "Error setting db version #{ $! }"
58
+ puts "THE DATABASE WAS NOT UPDATED WITH THE LATEST VERSION NUMBER: #{ version_no }"
59
+ end
60
+ end
61
+
62
+ def pluck_version_no( the_path )
63
+ path_syllables = the_path.split( "_" )
64
+ version_no = 0
65
+ path_syllables.each do |syllable|
66
+ #look for the first syllable that has no characters in it
67
+ #the first integer syllable
68
+ if not syllable =~ /\D/ then
69
+ version_no = syllable.to_i
70
+ break
71
+ end
72
+ end
73
+ return version_no
74
+ end
75
+
76
+ def migratable_path?( the_path )
77
+ if pluck_version_no( the_path ) > @current_db_version then
78
+ return true
79
+ else
80
+ return false
81
+ end
82
+ end
83
+
84
+ def migrate
85
+
86
+ puts "beginning migration process..."
87
+ puts @migration_directory
88
+ puts "collecting files to migrate"
89
+ migration_paths = Array.new
90
+ Find.find(@migration_directory) do |path|
91
+ if FileTest.file?(path) and path.match(/migration_\d.*sql/) and not path.match( /\.svn/ ) and migratable_path?(path)
92
+ print "."
93
+ migration_paths.push( path )
94
+ end
95
+ end
96
+ #sort paths
97
+ migration_paths = migration_paths.sort
98
+
99
+ if migration_paths.length > 0 then
100
+ migration_paths.each do |path|
101
+ puts "sqlplus #{ $db_user }//#{ $db_user_password }@#{ $db_name } @#{ path }"
102
+ end
103
+ #capture last migration number
104
+ final_db_version = pluck_version_no( migration_paths.last )
105
+ puts "final db version #{ final_db_version }"
106
+ #set database to version
107
+ set_db_version( final_db_version )
108
+ else
109
+ puts "database is current"
110
+ end
111
+
112
+ end
113
+
114
+ end
115
+
@@ -0,0 +1,65 @@
1
+ class DependencyAnalyzer
2
+
3
+ def initialize(directory)
4
+ p "Analyzing " + directory
5
+ @search_directory
6
+ end
7
+
8
+ def get_file_list
9
+
10
+ end
11
+
12
+ def get_dependency_list(file_name)
13
+
14
+
15
+ end
16
+
17
+ def produce_ordered_list
18
+
19
+ ordered_list = Array.new
20
+ done_collecting = false
21
+ loop_idx = 0
22
+
23
+ while not done_collecting
24
+
25
+ loop_idx += 1
26
+
27
+ @raw_table_list.each{ |table|
28
+
29
+ if not ordered_list.include?(table) then
30
+
31
+ dependencies = get_dependency_list(table).sort
32
+
33
+ if dependencies.length == 0 then
34
+ ordered_list.push( table )
35
+ else
36
+ #this line of code is checking to see if all of the dependencies
37
+ # for the table we are analyzing are already int the ordered_list
38
+ matches = ordered_list.select{ |i| dependencies.include?(i) }
39
+ matches = matches.sort
40
+ if matches.eql?(dependencies)
41
+ ordered_list.push( table )
42
+ end
43
+ end
44
+ end
45
+
46
+ }
47
+
48
+ if ordered_list.sort.eql?(@raw_table_list.sort) then
49
+ done_collecting = true
50
+ puts "done colecting dependency matches. all tables have been collected and matched."
51
+ end
52
+
53
+ if loop_idx > 10
54
+ done_collecting = true
55
+ puts "giving up on finishing collecting"
56
+ puts "difference (missing ones): "
57
+ puts @raw_table_list - ordered_list
58
+ end
59
+
60
+ end
61
+
62
+ return ordered_list
63
+
64
+ end
65
+