amalgalite 0.4.2-x86-mswin32-60 → 0.5.0-x86-mswin32-60

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/ext/sqlite3ext.h CHANGED
@@ -15,7 +15,7 @@
15
15
  ** as extensions by SQLite should #include this file instead of
16
16
  ** sqlite3.h.
17
17
  **
18
- ** @(#) $Id: sqlite3ext.h,v 1.24 2008/06/30 15:09:29 danielk1977 Exp $
18
+ ** @(#) $Id: sqlite3ext.h,v 1.25 2008/10/12 00:27:54 shane Exp $
19
19
  */
20
20
  #ifndef _SQLITE3EXT_H_
21
21
  #define _SQLITE3EXT_H_
@@ -208,7 +208,9 @@ struct sqlite3_api_routines {
208
208
  */
209
209
  #ifndef SQLITE_CORE
210
210
  #define sqlite3_aggregate_context sqlite3_api->aggregate_context
211
+ #ifndef SQLITE_OMIT_DEPRECATED
211
212
  #define sqlite3_aggregate_count sqlite3_api->aggregate_count
213
+ #endif
212
214
  #define sqlite3_bind_blob sqlite3_api->bind_blob
213
215
  #define sqlite3_bind_double sqlite3_api->bind_double
214
216
  #define sqlite3_bind_int sqlite3_api->bind_int
@@ -264,14 +266,18 @@ struct sqlite3_api_routines {
264
266
  #define sqlite3_errmsg sqlite3_api->errmsg
265
267
  #define sqlite3_errmsg16 sqlite3_api->errmsg16
266
268
  #define sqlite3_exec sqlite3_api->exec
269
+ #ifndef SQLITE_OMIT_DEPRECATED
267
270
  #define sqlite3_expired sqlite3_api->expired
271
+ #endif
268
272
  #define sqlite3_finalize sqlite3_api->finalize
269
273
  #define sqlite3_free sqlite3_api->free
270
274
  #define sqlite3_free_table sqlite3_api->free_table
271
275
  #define sqlite3_get_autocommit sqlite3_api->get_autocommit
272
276
  #define sqlite3_get_auxdata sqlite3_api->get_auxdata
273
277
  #define sqlite3_get_table sqlite3_api->get_table
278
+ #ifndef SQLITE_OMIT_DEPRECATED
274
279
  #define sqlite3_global_recover sqlite3_api->global_recover
280
+ #endif
275
281
  #define sqlite3_interrupt sqlite3_api->interruptx
276
282
  #define sqlite3_last_insert_rowid sqlite3_api->last_insert_rowid
277
283
  #define sqlite3_libversion sqlite3_api->libversion
@@ -309,7 +315,9 @@ struct sqlite3_api_routines {
309
315
  #define sqlite3_thread_cleanup sqlite3_api->thread_cleanup
310
316
  #define sqlite3_total_changes sqlite3_api->total_changes
311
317
  #define sqlite3_trace sqlite3_api->trace
318
+ #ifndef SQLITE_OMIT_DEPRECATED
312
319
  #define sqlite3_transfer_bindings sqlite3_api->transfer_bindings
320
+ #endif
313
321
  #define sqlite3_update_hook sqlite3_api->update_hook
314
322
  #define sqlite3_user_data sqlite3_api->user_data
315
323
  #define sqlite3_value_blob sqlite3_api->value_blob
@@ -11,7 +11,7 @@ module Amalgalite
11
11
  #
12
12
  # For instance during an insert:
13
13
  #
14
- # blob_column = db.schema.tables['blobs'].columsn['data']
14
+ # blob_column = db.schema.tables['blobs'].columns['data']
15
15
  # db.execute("INSERT INTO blobs(name, data) VALUES ( $name, $blob )",
16
16
  # { "$name" => "/path/to/file",
17
17
  # "$blob" => Amalgalite::Blob.new( :file => '/path/to/file',
@@ -1,14 +1,21 @@
1
1
  module Kernel
2
+ # alias the original require away to use later
2
3
  alias :amalgalite_original_require :require
4
+
3
5
  #
4
6
  # hook into the system 'require' to allow for required text or blobs from an
5
7
  # amalgalite database.
6
8
  #
7
9
  def require( filename )
8
- found = Amalgalite::Requires.require( filename )
9
- unless found
10
- found = amalgalite_original_require( filename )
10
+ loaded = amalgalite_original_require( filename )
11
+ rescue LoadError => load_error
12
+ if load_error.message =~ /#{Regexp.escape filename}\z/ then
13
+ loaded = Amalgalite::Requires.require( filename )
14
+ else
15
+ raise load_error
11
16
  end
12
- return found
13
17
  end
18
+
19
+ private :require
20
+ private :amalgalite_original_require
14
21
  end
@@ -0,0 +1,221 @@
1
+ require 'optparse'
2
+ require 'ostruct'
3
+ require 'pathname'
4
+ require 'zlib'
5
+
6
+ require 'amalgalite'
7
+ module Amalgalite
8
+ #
9
+ # Pack items into an amalgalite database.
10
+ #
11
+ class Packer
12
+ attr_reader :packing_list
13
+ attr_reader :dbfile
14
+ attr_reader :options
15
+
16
+ class << self
17
+ def default_options
18
+ {
19
+ :table_name => Requires::Bootstrap::DEFAULT_TABLE,
20
+ :filename_column => Requires::Bootstrap::DEFAULT_FILENAME_COLUMN,
21
+ :contents_column => Requires::Bootstrap::DEFAULT_CONTENTS_COLUMN,
22
+ :compressed_column => Requires::Bootstrap::DEFAULT_COMPRESSED_COLUMN,
23
+ :strip_prefix => Dir.pwd,
24
+ :compressed => false,
25
+ :verbose => false,
26
+ }
27
+ end
28
+
29
+ #
30
+ # compress data
31
+ #
32
+ def gzip( data )
33
+ zipped = StringIO.new
34
+ Zlib::GzipWriter.wrap( zipped ) do |io|
35
+ io.write( data )
36
+ end
37
+ return zipped.string
38
+ end
39
+
40
+ #
41
+ # uncompress gzip data
42
+ #
43
+ def gunzip( data )
44
+ data = StringIO.new( data )
45
+ Zlib::GzipReader.new( data ).read
46
+ end
47
+
48
+
49
+ #
50
+ # return the files in their dependency order for use for packing into a
51
+ # database
52
+ #
53
+ def amalgalite_require_order
54
+ @require_order ||= %w[
55
+ amalgalite.rb
56
+ amalgalite/blob.rb
57
+ amalgalite/boolean.rb
58
+ amalgalite/column.rb
59
+ amalgalite/statement.rb
60
+ amalgalite/trace_tap.rb
61
+ amalgalite/profile_tap.rb
62
+ amalgalite/type_map.rb
63
+ amalgalite/type_maps/storage_map.rb
64
+ amalgalite/type_maps/text_map.rb
65
+ amalgalite/type_maps/default_map.rb
66
+ amalgalite/database.rb
67
+ amalgalite/index.rb
68
+ amalgalite/paths.rb
69
+ amalgalite/table.rb
70
+ amalgalite/view.rb
71
+ amalgalite/schema.rb
72
+ amalgalite/version.rb
73
+ amalgalite/sqlite3/version.rb
74
+ amalgalite/sqlite3/constants.rb
75
+ amalgalite/sqlite3/status.rb
76
+ amalgalite/sqlite3/database/status.rb
77
+ amalgalite/sqlite3.rb
78
+ amalgalite/taps/io.rb
79
+ amalgalite/taps/console.rb
80
+ amalgalite/taps.rb
81
+ amalgalite/packer.rb
82
+ amalgalite/core_ext/kernel/require.rb
83
+ amalgalite/requires.rb
84
+ ]
85
+ end
86
+ end
87
+
88
+ #
89
+ # Create a new packer instance with the list of items to pack and all the
90
+ # options
91
+ #
92
+ def initialize( options = {} )
93
+ @options = Packer.default_options.merge( options )
94
+ @dbfile = @options[:dbfile] || Requires::Bootstrap::DEFAULT_DB
95
+ end
96
+
97
+ #
98
+ # The SQL to create the table for storing ruby code
99
+ #
100
+ def create_table_sql
101
+ sql = <<-create
102
+ CREATE TABLE #{options[:table_name]} (
103
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
104
+ #{options[:filename_column]} TEXT UNIQUE,
105
+ #{options[:compressed_column]} BOOLEAN,
106
+ #{options[:contents_column]} BLOB
107
+ );
108
+ create
109
+ end
110
+
111
+ #
112
+ # Make sure that the dbfile exists and has the appropriate schema.
113
+ #
114
+ def check_db( db )
115
+ if db.schema.tables[ options[:table_name] ] and options[:drop_table] then
116
+ STDERR.puts "Dropping table #{options[:table_name]}" if options[:verbose]
117
+ db.execute("DROP TABLE #{options[:table_name]}")
118
+ db.reload_schema!
119
+ end
120
+
121
+ unless db.schema.tables[ options[:table_name] ]
122
+ db.execute( create_table_sql )
123
+ db.reload_schema!
124
+ end
125
+
126
+ end
127
+
128
+
129
+ #
130
+ # Stores all the .rb files in the list into the given database. The prefix
131
+ # is the file system path to remove from the front of the path on each file
132
+ #
133
+ # manifest is an array of OpenStructs.
134
+ #
135
+ def pack_files( manifest )
136
+ db = Amalgalite::Database.new( dbfile )
137
+ check_db( db )
138
+ max_width = manifest.collect{ |m| m.require_path.length }.sort.last
139
+ contents_column = db.schema.tables[ options[:table_name] ].columns[ options[:contents_column] ]
140
+ db.transaction do |trans|
141
+ manifest.each do |file_info|
142
+ msg = " -> #{file_info.require_path.ljust( max_width )} : "
143
+ begin
144
+ if options[:merge] then
145
+ trans.execute( "DELETE FROM #{options[:table_name]} WHERE #{options[:filename_column]} = ?", file_info.require_path )
146
+ end
147
+
148
+ trans.prepare("INSERT INTO #{options[:table_name]}(#{options[:filename_column]}, #{options[:compressed_column]}, #{options[:contents_column]}) VALUES( $filename, $compressed, $contents)") do |stmt|
149
+ contents = IO.readlines( file_info.file_path )
150
+ if options[:self] then
151
+ contents.each { |l| l.gsub!( /^(\s*require .*)$/m, "# commented out by #{self.class.name} \\1") }
152
+ end
153
+ contents = contents.join
154
+
155
+ if options[:compressed] then
156
+ contents = Packer.gzip( contents )
157
+ end
158
+ content_io = StringIO.new( contents )
159
+ stmt.execute( "$filename" => file_info.require_path,
160
+ "$contents" => Amalgalite::Blob.new( :io => content_io,
161
+ :column => contents_column ),
162
+ "$compressed" => options[:compressed] )
163
+ STDERR.puts "#{msg} stored #{file_info.file_path}" if options[:verbose]
164
+ end
165
+ rescue => e
166
+ STDERR.puts "#{msg} error #{e}"
167
+ end
168
+ end
169
+ end
170
+ end
171
+
172
+ #
173
+ # given a file, see if it can be found in the ruby load path, if so, return that
174
+ # full path
175
+ #
176
+ def full_path_of( rb_file )
177
+ $LOAD_PATH.each do |load_path|
178
+ guess = File.expand_path( File.join( load_path, rb_file ) )
179
+ return guess if File.exist?( guess )
180
+ end
181
+ return nil
182
+ end
183
+
184
+ #
185
+ # Make the manifest for packing
186
+ #
187
+ def make_manifest( file_list )
188
+ manifest = []
189
+ prefix_path = ::Pathname.new( options[:strip_prefix] )
190
+ file_list.each do |f|
191
+ file_path = ::Pathname.new( File.expand_path( f ) )
192
+ m = ::OpenStruct.new
193
+ # if it is a directory then grab all the .rb files from it
194
+ if File.directory?( file_path ) then
195
+ manifest.concat( make_manifest( Dir.glob( File.join( f, "**", "*.rb" ) ) ) )
196
+ next
197
+ elsif File.readable?( file_path ) then
198
+ m.require_path = file_path.relative_path_from( prefix_path )
199
+ m.file_path = file_path.realpath.to_s
200
+ elsif lp = full_path_of( f ) then
201
+ m.require_path = f
202
+ m.file_path = lp
203
+ else
204
+ STDERR.puts "Unable to add #{f} to the manifest, cannot find the file on disk"
205
+ next
206
+ end
207
+ m.require_path = m.require_path.to_s[ /\A(.*)\.rb\Z/, 1]
208
+ manifest << m
209
+ end
210
+ return manifest
211
+ end
212
+
213
+ #
214
+ # Given a list of files pack them into the associated database and table.
215
+ #
216
+ def pack( file_list )
217
+ manifest = make_manifest( file_list )
218
+ pack_files( manifest )
219
+ end
220
+ end
221
+ end
@@ -1,77 +1,75 @@
1
1
  require 'amalgalite'
2
+ require 'pathname'
3
+ require 'zlib'
4
+ require 'amalgalite/packer'
2
5
 
3
6
  module Amalgalite
4
7
  #
5
- # Requires encapsulates requiring itesm from the database
8
+ # Requires encapsulates requiring items from the database
9
+ #
6
10
  class Requires
7
11
  class << self
8
12
  def load_path_db_connections
9
13
  @load_path_db_connections ||= {}
10
14
  end
15
+
11
16
  def load_path
12
17
  @load_path ||= []
13
18
  end
14
19
 
20
+ #
21
+ # Allocate a database connection to the given filename
22
+ #
15
23
  def db_connection_to( dbfile_name )
16
24
  unless connection = load_path_db_connections[ dbfile_name ]
17
- puts "loading file #{dbfile_name}"
18
25
  connection = ::Amalgalite::Database.new( dbfile_name )
19
26
  load_path_db_connections[dbfile_name] = connection
20
27
  end
21
28
  return connection
22
29
  end
23
30
 
24
- def require( filename )
25
- load_path.each { |lp| lp.require( filename ) }
31
+ #
32
+ # Setting a class level variable as a flag to know what we are currently
33
+ # in the middle of requiring
34
+ #
35
+ def requiring
36
+ @requiring ||= []
26
37
  end
27
38
 
28
- #
29
- # return the files in their dependency order for use for packing into a
30
- # database
31
- #
32
- def require_order
33
- @require_roder ||= %w[
34
- amalgalite.rb
35
- amalgalite/blob.rb
36
- amalgalite/boolean.rb
37
- amalgalite/column.rb
38
- amalgalite/statement.rb
39
- amalgalite/trace_tap.rb
40
- amalgalite/profile_tap.rb
41
- amalgalite/type_map.rb
42
- amalgalite/type_maps/storage_map.rb
43
- amalgalite/type_maps/text_map.rb
44
- amalgalite/type_maps/default_map.rb
45
- amalgalite/database.rb
46
- amalgalite/index.rb
47
- amalgalite/paths.rb
48
- amalgalite/table.rb
49
- amalgalite/view.rb
50
- amalgalite/schema.rb
51
- amalgalite/version.rb
52
- amalgalite/sqlite3/version.rb
53
- amalgalite/sqlite3/constants.rb
54
- amalgalite/sqlite3.rb
55
- amalgalite/taps/io.rb
56
- amalgalite/taps/console.rb
57
- amalgalite/taps.rb
58
- amalgalite/core_ext/kernel/require.rb
59
- amalgalite/requires.rb
60
- ]
61
- end
62
- end
39
+ def require( filename )
40
+ if load_path.empty? then
41
+ raise ::LoadError, "Amalgalite load path is empty -- #{filename}"
42
+ elsif $LOADED_FEATURES.include?( filename ) then
43
+ return false
44
+ elsif Requires.requiring.include?( filename ) then
45
+ return false
46
+ else
47
+ Requires.requiring << filename
48
+ load_path.each do |lp|
49
+ if lp.require( filename ) then
50
+ Requires.requiring.delete( filename )
51
+ return true
52
+ end
53
+ end
54
+ Requires.requiring.delete( filename )
55
+ raise ::LoadError, "amalgalite has no such file to load -- #{filename}"
56
+ end
57
+ end
58
+ end
63
59
 
64
60
  attr_reader :dbfile_name
65
61
  attr_reader :table_name
66
62
  attr_reader :filename_column
67
63
  attr_reader :contents_column
64
+ attr_reader :compressed_column
68
65
  attr_reader :db_connection
69
66
 
70
67
  def initialize( opts = {} )
71
- @dbfile_name = opts[:dbfile_name] || "lib.db"
72
- @table_name = opts[:table_name] || "rubylibs"
73
- @filename_column = opts[:filename_column] || "filename"
74
- @contents_column = opts[:contents_column] || "contents"
68
+ @dbfile_name = opts[:dbfile_name] || Bootstrap::DEFAULT_DB
69
+ @table_name = opts[:table_name] || Bootstrap::DEFAULT_TABLE
70
+ @filename_column = opts[:filename_column] || Bootstrap::DEFAULT_FILENAME_COLUMN
71
+ @contents_column = opts[:contents_column] || Bootstrap::DEFAULT_CONTENTS_COLUMN
72
+ @compressed_column = opts[:compressed_column] || Bootstrap::DEFAULT_COMPRESSED_COLUMN
75
73
  @db_connection = Requires.db_connection_to( dbfile_name )
76
74
  Requires.load_path << self
77
75
  end
@@ -80,32 +78,42 @@ module Amalgalite
80
78
  # return the sql to find the file contents for a file in this requires
81
79
  #
82
80
  def sql
83
- @sql ||= "SELECT #{filename_column}, #{contents_column} FROM #{table_name} WHERE #{filename_column} = ?"
81
+ @sql ||= "SELECT #{filename_column}, #{compressed_column}, #{contents_column} FROM #{table_name} WHERE #{filename_column} = ?"
84
82
  end
85
83
 
86
84
  #
87
- # require a file in this database table. This will check and see if the
85
+ # load a file in this database table. This will check and see if the
88
86
  # file is already required. If it isn't it will select the contents
89
87
  # associated with the row identified by the filename and eval those contents
90
88
  # within the context of TOPLEVEL_BINDING. The filename is then appended to
91
- # $".
89
+ # $LOADED_FEATURES.
92
90
  #
93
91
  # if the file was required then true is returned, otherwise false
94
92
  #
95
93
  def require( filename )
96
- if $".include?( filename ) then
94
+ if $LOADED_FEATURES.include?( filename ) then
97
95
  return false
98
96
  else
99
97
  begin
98
+ filename = filename.gsub(/\.rb\Z/,'')
100
99
  rows = db_connection.execute(sql, filename)
101
- row = rows.first
102
- eval( row[contents_column].to_s, TOPLEVEL_BINDING)
103
- $" << row[filename_column]
100
+ if rows.size > 0 then
101
+ row = rows.first
102
+ contents = row[contents_column].to_s
103
+ if row[compressed_column] then
104
+ contents = ::Amalgalite::Packer.gunzip( contents )
105
+ end
106
+
107
+ eval( contents, TOPLEVEL_BINDING, row[filename_column] )
108
+ $LOADED_FEATURES << row[filename_column]
109
+ return true
110
+ else
111
+ return false
112
+ end
104
113
  rescue => e
105
- raise LoadError, "Failure loading #{filename} from #{dbfile_name} : #{e}"
114
+ raise ::LoadError, "Failure loading #{filename} from #{dbfile_name} : #{e}"
106
115
  end
107
116
  end
108
- return true
109
117
  end
110
118
  end
111
119
  end