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/HISTORY +12 -0
- data/bin/amalgalite-pack +121 -0
- data/examples/blob.rb +18 -35
- data/examples/bootstrap.rb +6 -6
- data/examples/require_me.rb +11 -0
- data/examples/requires.rb +23 -35
- data/ext/amalgalite3.h +3 -0
- data/ext/amalgalite3_requires_bootstrap.c +17 -15
- data/ext/sqlite3.c +4684 -3983
- data/ext/sqlite3.h +301 -96
- data/ext/sqlite3ext.h +9 -1
- data/lib/amalgalite/blob.rb +1 -1
- data/lib/amalgalite/core_ext/kernel/require.rb +11 -4
- data/lib/amalgalite/packer.rb +221 -0
- data/lib/amalgalite/requires.rb +60 -52
- data/lib/amalgalite/statement.rb +5 -2
- data/lib/amalgalite/version.rb +2 -2
- data/lib/amalgalite3.so +0 -0
- data/spec/packer_spec.rb +50 -0
- data/spec/requires_spec.rb +23 -0
- data/spec/sqlite3/version_spec.rb +2 -2
- data/spec/version_spec.rb +6 -0
- data/tasks/config.rb +4 -5
- data/tasks/extension.rake +4 -1
- metadata +10 -6
- data/bin/amalgalite-pack-into-db +0 -155
- data/ext/rbconfig-mingw.rb +0 -178
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.
|
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
|
data/lib/amalgalite/blob.rb
CHANGED
@@ -11,7 +11,7 @@ module Amalgalite
|
|
11
11
|
#
|
12
12
|
# For instance during an insert:
|
13
13
|
#
|
14
|
-
# blob_column = db.schema.tables['blobs'].
|
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
|
-
|
9
|
-
|
10
|
-
|
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
|
data/lib/amalgalite/requires.rb
CHANGED
@@ -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
|
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
|
-
|
25
|
-
|
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
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
amalgalite
|
45
|
-
|
46
|
-
|
47
|
-
|
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
|
72
|
-
@table_name
|
73
|
-
@filename_column
|
74
|
-
@contents_column
|
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
|
-
#
|
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 $
|
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
|
-
|
102
|
-
|
103
|
-
|
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
|