orasaurus 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.
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
+