amalgalite 1.9.4 → 2.0.0

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 (74) hide show
  1. checksums.yaml +4 -4
  2. data/HISTORY.md +19 -2
  3. data/Manifest.txt +4 -54
  4. data/README.md +1 -1
  5. data/TODO.md +4 -3
  6. data/amalgalite.gemspec +39 -0
  7. data/ext/amalgalite/c/amalgalite.c +0 -1
  8. data/ext/amalgalite/c/amalgalite_constants.c +155 -10
  9. data/ext/amalgalite/c/extconf.rb +5 -2
  10. data/ext/amalgalite/c/gen_constants.rb +32 -1
  11. data/ext/amalgalite/c/sqlite3.c +19308 -9112
  12. data/ext/amalgalite/c/sqlite3.h +909 -296
  13. data/ext/amalgalite/c/sqlite3ext.h +11 -0
  14. data/lib/amalgalite/column.rb +20 -2
  15. data/lib/amalgalite/result/row.rb +83 -0
  16. data/lib/amalgalite/result.rb +15 -0
  17. data/lib/amalgalite/statement.rb +32 -24
  18. data/lib/amalgalite/type_maps/default_map.rb +48 -56
  19. data/lib/amalgalite/version.rb +1 -1
  20. metadata +32 -119
  21. data/Rakefile +0 -27
  22. data/bin/amalgalite-pack +0 -147
  23. data/examples/a.rb +0 -9
  24. data/examples/blob.rb +0 -88
  25. data/examples/bootstrap.rb +0 -36
  26. data/examples/define_aggregate.rb +0 -75
  27. data/examples/define_function.rb +0 -104
  28. data/examples/fts5.rb +0 -152
  29. data/examples/gem-db.rb +0 -94
  30. data/examples/require_me.rb +0 -11
  31. data/examples/requires.rb +0 -42
  32. data/examples/schema-info.rb +0 -34
  33. data/ext/amalgalite/c/amalgalite_requires_bootstrap.c +0 -283
  34. data/lib/amalgalite/core_ext/kernel/require.rb +0 -21
  35. data/lib/amalgalite/packer.rb +0 -231
  36. data/lib/amalgalite/requires.rb +0 -151
  37. data/spec/aggregate_spec.rb +0 -158
  38. data/spec/amalgalite_spec.rb +0 -4
  39. data/spec/blob_spec.rb +0 -78
  40. data/spec/boolean_spec.rb +0 -24
  41. data/spec/busy_handler.rb +0 -157
  42. data/spec/data/iso-3166-country.txt +0 -242
  43. data/spec/data/iso-3166-schema.sql +0 -22
  44. data/spec/data/iso-3166-subcountry.txt +0 -3995
  45. data/spec/data/make-iso-db.sh +0 -12
  46. data/spec/database_spec.rb +0 -505
  47. data/spec/default_map_spec.rb +0 -92
  48. data/spec/function_spec.rb +0 -78
  49. data/spec/integeration_spec.rb +0 -97
  50. data/spec/iso_3166_database.rb +0 -58
  51. data/spec/json_spec.rb +0 -24
  52. data/spec/packer_spec.rb +0 -60
  53. data/spec/paths_spec.rb +0 -28
  54. data/spec/progress_handler_spec.rb +0 -91
  55. data/spec/requires_spec.rb +0 -54
  56. data/spec/rtree_spec.rb +0 -66
  57. data/spec/schema_spec.rb +0 -131
  58. data/spec/spec_helper.rb +0 -48
  59. data/spec/sqlite3/constants_spec.rb +0 -108
  60. data/spec/sqlite3/database_status_spec.rb +0 -36
  61. data/spec/sqlite3/status_spec.rb +0 -22
  62. data/spec/sqlite3/version_spec.rb +0 -28
  63. data/spec/sqlite3_spec.rb +0 -53
  64. data/spec/statement_spec.rb +0 -168
  65. data/spec/storage_map_spec.rb +0 -38
  66. data/spec/tap_spec.rb +0 -57
  67. data/spec/text_map_spec.rb +0 -20
  68. data/spec/type_map_spec.rb +0 -14
  69. data/spec/version_spec.rb +0 -8
  70. data/tasks/custom.rake +0 -101
  71. data/tasks/default.rake +0 -257
  72. data/tasks/extension.rake +0 -28
  73. data/tasks/this.rb +0 -208
  74. /data/{LICENSE → LICENSE.txt} +0 -0
@@ -1,283 +0,0 @@
1
- /**
2
- * Copyright (c) 2008 Jeremy Hinegardner
3
- * All rights reserved. See LICENSE and/or COPYING for details.
4
- *
5
- * vim: shiftwidth=4
6
- */
7
-
8
- #include "amalgalite.h"
9
- #include <stdio.h>
10
- #include <stdnoreturn.h>
11
- extern VALUE mA;
12
- VALUE cAR;
13
- VALUE cARB;
14
- VALUE eARB_Error;
15
-
16
- /*
17
- * cleanup the datatbase and statment values if they are currently open and then
18
- * raise the message. It is assumed that the *msg pointer passed in is NOT
19
- * allocated via malloc() or the like. It should be a local static buffer
20
- * that we do not have to worry about freeing.
21
- */
22
- noreturn void am_bootstrap_cleanup_and_raise( const char* msg, sqlite3* db, sqlite3_stmt* stmt )
23
- {
24
-
25
- if ( NULL != stmt ) { sqlite3_finalize( stmt ); stmt = NULL; }
26
- if ( NULL != db ) { sqlite3_close( db ); }
27
-
28
- rb_raise(eARB_Error, "%s", msg );
29
- }
30
-
31
-
32
- void am_bootstrap_from_db( sqlite3* db, VALUE args )
33
- {
34
- sqlite3_stmt* stmt = NULL;
35
- int rc;
36
- char raise_msg[BUFSIZ];
37
- int last_row_good;
38
-
39
- VALUE am_tbl_c = rb_const_get( cARB, rb_intern("DEFAULT_BOOTSTRAP_TABLE") );
40
- VALUE am_pk_c = rb_const_get( cARB, rb_intern("DEFAULT_ROWID_COLUMN") );
41
- VALUE am_fname_c = rb_const_get( cARB, rb_intern("DEFAULT_FILENAME_COLUMN") );
42
- VALUE am_content_c = rb_const_get( cARB, rb_intern("DEFAULT_CONTENTS_COLUMN") );
43
-
44
- char* tbl_name = NULL;
45
- char* pk_col = NULL;
46
- char* fname_col = NULL;
47
- char* content_col = NULL;
48
-
49
-
50
- char sql[BUFSIZ];
51
- const char* sql_tail = NULL;
52
- int sql_bytes = 0;
53
-
54
- const unsigned char* result_text = NULL;
55
- int result_length = 0;
56
-
57
- VALUE require_name = Qnil; /* ruby string of the file name for use in eval */
58
- VALUE eval_this_code = Qnil; /* ruby string of the code to eval from the db */
59
- VALUE toplevel_binding = rb_const_get( rb_cObject, rb_intern("TOPLEVEL_BINDING") ) ;
60
- VALUE tmp = Qnil;
61
-
62
- ID eval_id = rb_intern("eval");
63
-
64
-
65
-
66
- tbl_name = ( Qnil == (tmp = rb_hash_aref( args, rb_str_new2( "table_name" ) ) ) ) ? StringValuePtr( am_tbl_c ) : StringValuePtr( tmp );
67
- pk_col = ( Qnil == (tmp = rb_hash_aref( args, rb_str_new2( "rowid_column" ) ) ) ) ? StringValuePtr( am_pk_c ) : StringValuePtr( tmp );
68
- fname_col = ( Qnil == (tmp = rb_hash_aref( args, rb_str_new2( "filename_column" ) ) ) ) ? StringValuePtr( am_fname_c ) : StringValuePtr( tmp );
69
- content_col = ( Qnil == (tmp = rb_hash_aref( args, rb_str_new2( "contents_column" ) ) ) ) ? StringValuePtr( am_content_c ) : StringValuePtr( tmp );
70
-
71
-
72
- /* prepare the db query */
73
- memset( sql, 0, BUFSIZ );
74
- sql_bytes = snprintf( sql, BUFSIZ, "SELECT %s, %s FROM %s ORDER BY %s", fname_col, content_col, tbl_name, pk_col );
75
- rc = sqlite3_prepare_v2( db, sql, sql_bytes, &stmt, &sql_tail ) ;
76
- if ( SQLITE_OK != rc) {
77
- memset( raise_msg, 0, BUFSIZ );
78
- snprintf( raise_msg, BUFSIZ,
79
- "Failure to prepare bootload select statement table = '%s', rowid col = '%s', filename col ='%s', contents col = '%s' : [SQLITE_ERROR %d] %s\n",
80
- tbl_name, pk_col, fname_col, content_col, rc, sqlite3_errmsg( db ));
81
- am_bootstrap_cleanup_and_raise( raise_msg, db, stmt );
82
- }
83
-
84
- /* loop over the resulting rows, eval'ing and loading $LOADED_FEATURES */
85
- last_row_good = -1;
86
- while ( SQLITE_ROW == ( rc = sqlite3_step( stmt ) ) ) {
87
- /* file name */
88
- result_text = sqlite3_column_text( stmt, 0 );
89
- result_length = sqlite3_column_bytes( stmt, 0 );
90
- require_name = rb_str_new( (const char*)result_text, result_length );
91
-
92
- /* ruby code */
93
- result_text = sqlite3_column_text( stmt, 1 );
94
- result_length = sqlite3_column_bytes( stmt, 1 );
95
- eval_this_code = rb_str_new( (const char*)result_text, result_length );
96
-
97
- /* Kernel.eval( code, TOPLEVEL_BINDING, filename, 1 ) */
98
- rb_funcall(rb_mKernel, eval_id, 4, eval_this_code, toplevel_binding, require_name, INT2FIX(1) );
99
-
100
- /* TODO: for ruby 1.9 -- put in ? sqlite3://path/to/database?tablename=tbl_name#require_name */
101
- /* update $LOADED_FEATURES */
102
- rb_ary_push( rb_gv_get( "$LOADED_FEATURES" ), require_name );
103
- }
104
-
105
- /* if there was some sqlite error in the processing of the rows */
106
- if ( SQLITE_DONE != rc ) {
107
- memset( raise_msg, 0, BUFSIZ );
108
- snprintf( raise_msg, BUFSIZ, "Failure in bootloading, last successfully loaded rowid was %d : [SQLITE_ERROR %d] %s\n",
109
- last_row_good, rc, sqlite3_errmsg( db ) );
110
- am_bootstrap_cleanup_and_raise( raise_msg, db, stmt );
111
- }
112
-
113
- /* finalize the statement */
114
- rc = sqlite3_finalize( stmt );
115
- if ( SQLITE_OK != rc ) {
116
- memset( raise_msg, 0, BUFSIZ );
117
- snprintf( raise_msg, BUFSIZ, "Failure to finalize bootload statement : [SQLITE_ERROR %d] %s\n", rc, sqlite3_errmsg( db ) );
118
- am_bootstrap_cleanup_and_raise( raise_msg, db, stmt );
119
- }
120
-
121
- }
122
-
123
-
124
- /**
125
- * call-seq:
126
- * Amalgalite::Requires::Bootstrap.lift( 'dbfile' => "lib.db", 'table_name' => "bootload", 'rowid_column' => "id", 'filename_column' => "filename", 'content_column' => "contents" )
127
- *
128
- * *WARNING* *WARNING* *WARNING* *WARNING* *WARNING* *WARNING* *WARNING*
129
- *
130
- * This is a boostrap mechanism to eval all the code in a particular column in a
131
- * specially formatted table in an sqlite database. It should only be used for
132
- * a specific purpose, mainly loading the Amalgalite ruby code directly from an
133
- * sqlite table.
134
- *
135
- * Amalgalite::Requires adds in the ability to _require_ code that is in an
136
- * sqlite database. Since Amalgalite::Requires is itself ruby code, if
137
- * Amalgalite::Requires was in an sqlite database, it could not _require_
138
- * itself. Therefore this method is made available. It is a pure C extension
139
- * method that directly calls the sqlite3 C functions directly and uses the ruby
140
- * C api to eval the data in the table.
141
- *
142
- * This method attaches to an sqlite3 database (filename) and then does:
143
- *
144
- * SELECT filename_column_name, content_column_name
145
- * FROM table_name
146
- * ORDER BY rowid_column_name
147
- *
148
- * For each row returned it does an _eval_ on the code in the
149
- * *content_column_name* and then updates _$LOADED_FEATURES_ directly with the value from
150
- * *filename_column_name*.
151
- *
152
- * The database to be opened by _lift_ *must* be an sqlite3 UTF-8 database.
153
- *
154
- */
155
- VALUE am_bootstrap_lift( VALUE self, VALUE args )
156
- {
157
- sqlite3 *db = NULL;
158
- int rc;
159
- char raise_msg[BUFSIZ];
160
- VALUE tmp = Qnil;
161
-
162
- VALUE am_db_c = rb_const_get( cARB, rb_intern("DEFAULT_DB") );
163
-
164
- char *dbfile = NULL;
165
-
166
-
167
- if ( Qnil == args ) {
168
- args = rb_hash_new();
169
- } else {
170
- args = rb_ary_shift( args );
171
- }
172
-
173
- Check_Type( args, T_HASH );
174
-
175
- /* get the arguments */
176
- dbfile = ( Qnil == (tmp = rb_hash_aref( args, rb_str_new2( "dbfile" ) ) ) ) ? StringValuePtr( am_db_c ) : StringValuePtr( tmp );
177
-
178
- /* open the database */
179
- rc = sqlite3_open_v2( dbfile , &db, SQLITE_OPEN_READONLY, NULL);
180
- if ( SQLITE_OK != rc ) {
181
- memset( raise_msg, 0, BUFSIZ );
182
- snprintf(raise_msg, BUFSIZ, "Failure to open database %s for bootload: [SQLITE_ERROR %d] : %s", dbfile, rc, sqlite3_errmsg( db ) );
183
- am_bootstrap_cleanup_and_raise( raise_msg, db, NULL );
184
- }
185
-
186
- am_bootstrap_from_db( db, args );
187
-
188
- /* close the database */
189
- rc = sqlite3_close( db );
190
- if ( SQLITE_OK != rc ) {
191
- memset( raise_msg, 0, BUFSIZ );
192
- snprintf( raise_msg, BUFSIZ, "Failure to close database : [SQLITE_ERROR %d] : %s\n", rc, sqlite3_errmsg( db )),
193
- am_bootstrap_cleanup_and_raise( raise_msg, db, NULL );
194
- }
195
-
196
- return Qnil;
197
- }
198
-
199
- /**
200
- * call-seq:
201
- * Amalgalite::Requires::Bootstrap.lift_str( sql, 'table_name' => "bootload", 'rowid_column' => "id", 'filename_column' => "filename", 'content_column' => "contents" )
202
- *
203
- * Bootstrap Amalgalite from a string containing an SQL dump. See Amalgalite::Requires::Bootstrap.lift.
204
- *
205
- * For example:
206
- *
207
- * Amalgalite::Requires::Bootstrap.lifts(File.read("lib.sql"))
208
- */
209
- VALUE am_bootstrap_lift_str( VALUE self, VALUE args )
210
- {
211
- sqlite3 *db = NULL;
212
- int rc;
213
- char raise_msg[BUFSIZ];
214
- VALUE sql = Qnil;
215
- VALUE args_hsh = Qnil;
216
-
217
- sql = rb_ary_shift(args);
218
- StringValue(sql);
219
- if ( Qnil == sql ) { rb_raise(eARB_Error, "SQL required." ); }
220
-
221
- args_hsh = rb_ary_shift(args);
222
- if ( Qnil == args_hsh ) { args_hsh = rb_hash_new(); }
223
-
224
-
225
- rc = sqlite3_open_v2( ":memory:", &db, SQLITE_OPEN_READWRITE, NULL );
226
- if ( SQLITE_OK != rc ) {
227
- memset( raise_msg, 0, BUFSIZ );
228
- snprintf(raise_msg, BUFSIZ, "Failure to open database :memory: for bootload: [SQLITE_ERROR %d] : %s", rc, sqlite3_errmsg( db ) );
229
- am_bootstrap_cleanup_and_raise( raise_msg, db, NULL );
230
- }
231
-
232
- /* Load the bootstrap SQL into the database */
233
- rc = sqlite3_exec( db, StringValuePtr( sql ), NULL, NULL, NULL );
234
-
235
- if ( SQLITE_OK != rc ) {
236
- memset( raise_msg, 0, BUFSIZ );
237
- snprintf(raise_msg, BUFSIZ, "Failure to import bootload sql: [SQLITE_ERROR %d] : %s", rc, sqlite3_errmsg( db ) );
238
- am_bootstrap_cleanup_and_raise( raise_msg, db, NULL );
239
- }
240
-
241
- am_bootstrap_from_db( db, args_hsh );
242
-
243
- rc = sqlite3_close( db );
244
-
245
- if ( SQLITE_OK != rc ) {
246
- memset( raise_msg, 0, BUFSIZ );
247
- snprintf( raise_msg, BUFSIZ, "Failure to close database : [SQLITE_ERROR %d] : %s\n", rc, sqlite3_errmsg( db )),
248
- am_bootstrap_cleanup_and_raise( raise_msg, db, NULL );
249
- }
250
-
251
- return Qnil;
252
-
253
- }
254
-
255
-
256
- /**
257
- * Bootstrapping module to help _require_ when Amalgalite::Requires is not
258
- * availble in files.
259
- */
260
- void Init_amalgalite_requires_bootstrap()
261
- {
262
-
263
- mA = rb_define_module("Amalgalite");
264
- cAR = rb_define_class_under(mA, "Requires", rb_cObject);
265
- cARB = rb_define_class_under(cAR, "Bootstrap", rb_cObject);
266
-
267
- eARB_Error = rb_define_class_under(cARB, "Error", rb_eStandardError);
268
-
269
- rb_define_module_function(cARB, "lift", am_bootstrap_lift, -2);
270
- rb_define_module_function(cARB, "lifts", am_bootstrap_lift, -2);
271
-
272
- /* constants for default db, table, column, rowid, contents */
273
- rb_define_const(cARB, "DEFAULT_DB", rb_str_new2( "lib.db" ));
274
- rb_define_const(cARB, "DEFAULT_TABLE", rb_str_new2( "rubylibs" ));
275
- rb_define_const(cARB, "DEFAULT_BOOTSTRAP_TABLE", rb_str_new2( "bootstrap" ));
276
- rb_define_const(cARB, "DEFAULT_ROWID_COLUMN", rb_str_new2( "id" ));
277
- rb_define_const(cARB, "DEFAULT_FILENAME_COLUMN", rb_str_new2( "filename" ));
278
- rb_define_const(cARB, "DEFAULT_CONTENTS_COLUMN", rb_str_new2( "contents" ));
279
- rb_define_const(cARB, "DEFAULT_COMPRESSED_COLUMN", rb_str_new2( "compressed" ));
280
-
281
- return;
282
- }
283
-
@@ -1,21 +0,0 @@
1
- module Kernel
2
- # alias the original require away to use later
3
- alias :amalgalite_original_require :require
4
-
5
- #
6
- # hook into the system 'require' to allow for required text or blobs from an
7
- # amalgalite database.
8
- #
9
- def 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
16
- end
17
- end
18
-
19
- private :require
20
- private :amalgalite_original_require
21
- end
@@ -1,231 +0,0 @@
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/sqlite3/database/function.rb
57
- amalgalite/aggregate.rb
58
- amalgalite/blob.rb
59
- amalgalite/boolean.rb
60
- amalgalite/busy_timeout.rb
61
- amalgalite/column.rb
62
- amalgalite/statement.rb
63
- amalgalite/trace_tap.rb
64
- amalgalite/profile_tap.rb
65
- amalgalite/type_map.rb
66
- amalgalite/type_maps/storage_map.rb
67
- amalgalite/type_maps/text_map.rb
68
- amalgalite/type_maps/default_map.rb
69
- amalgalite/function.rb
70
- amalgalite/progress_handler.rb
71
- amalgalite/csv_table_importer.rb
72
- amalgalite/database.rb
73
- amalgalite/index.rb
74
- amalgalite/memory_database.rb
75
- amalgalite/paths.rb
76
- amalgalite/table.rb
77
- amalgalite/view.rb
78
- amalgalite/schema.rb
79
- amalgalite/version.rb
80
- amalgalite/sqlite3/version.rb
81
- amalgalite/sqlite3/constants.rb
82
- amalgalite/sqlite3/status.rb
83
- amalgalite/sqlite3/database/status.rb
84
- amalgalite/sqlite3.rb
85
- amalgalite/taps/io.rb
86
- amalgalite/taps/console.rb
87
- amalgalite/taps.rb
88
- amalgalite/packer.rb
89
- amalgalite/core_ext/kernel/require.rb
90
- amalgalite/requires.rb
91
- ]
92
- end
93
- end
94
-
95
- #
96
- # Create a new packer instance with the list of items to pack and all the
97
- # options
98
- #
99
- def initialize( options = {} )
100
- @options = Packer.default_options.merge( options )
101
- @dbfile = @options[:dbfile] || Requires::Bootstrap::DEFAULT_DB
102
- end
103
-
104
- #
105
- # The SQL to create the table for storing ruby code
106
- #
107
- def create_table_sql
108
- <<-create
109
- CREATE TABLE #{options[:table_name]} (
110
- id INTEGER PRIMARY KEY AUTOINCREMENT,
111
- #{options[:filename_column]} TEXT UNIQUE,
112
- #{options[:compressed_column]} BOOLEAN,
113
- #{options[:contents_column]} BLOB
114
- );
115
- create
116
- end
117
-
118
- #
119
- # Make sure that the dbfile exists and has the appropriate schema.
120
- #
121
- def check_db( db )
122
- if db.schema.tables[ options[:table_name] ] and options[:drop_table] then
123
- STDERR.puts "Dropping table #{options[:table_name]}" if options[:verbose]
124
- db.execute("DROP TABLE #{options[:table_name]}")
125
- db.reload_schema!
126
- end
127
-
128
- unless db.schema.tables[ options[:table_name] ]
129
- db.execute( create_table_sql )
130
- db.reload_schema!
131
- end
132
-
133
- end
134
-
135
-
136
- #
137
- # Stores all the .rb files in the list into the given database. The prefix
138
- # is the file system path to remove from the front of the path on each file
139
- #
140
- # manifest is an array of OpenStructs.
141
- #
142
- def pack_files( manifest )
143
- db = Amalgalite::Database.new( dbfile )
144
- check_db( db )
145
- max_width = manifest.collect{ |m| m.require_path.length }.sort.last
146
- contents_column = db.schema.tables[ options[:table_name] ].columns[ options[:contents_column] ]
147
- db.transaction do |trans|
148
- manifest.each do |file_info|
149
- msg = " -> #{file_info.require_path.ljust( max_width )} : "
150
- begin
151
- if options[:merge] then
152
- trans.execute( "DELETE FROM #{options[:table_name]} WHERE #{options[:filename_column]} = ?", file_info.require_path )
153
- end
154
-
155
- trans.prepare("INSERT INTO #{options[:table_name]}(#{options[:filename_column]}, #{options[:compressed_column]}, #{options[:contents_column]}) VALUES( $filename, $compressed, $contents)") do |stmt|
156
- contents = IO.readlines( file_info.file_path )
157
- if options[:self] then
158
- contents.each { |l| l.gsub!( /^(\s*require .*)$/m, "# commented out by #{self.class.name} \\1") }
159
- end
160
- contents = contents.join
161
-
162
- if options[:compressed] then
163
- contents = Packer.gzip( contents )
164
- end
165
- content_io = StringIO.new( contents )
166
- stmt.execute( "$filename" => file_info.require_path,
167
- "$contents" => Amalgalite::Blob.new( :io => content_io,
168
- :column => contents_column ),
169
- "$compressed" => options[:compressed] )
170
- STDERR.puts "#{msg} stored #{file_info.file_path}" if options[:verbose]
171
- end
172
- rescue => e
173
- STDERR.puts "#{msg} error #{e}"
174
- end
175
- end
176
- end
177
- end
178
-
179
- #
180
- # given a file, see if it can be found in the ruby load path, if so, return that
181
- # full path
182
- #
183
- def full_path_of( rb_file )
184
- $LOAD_PATH.each do |load_path|
185
- guess = File.expand_path( File.join( load_path, rb_file ) )
186
- return guess if File.exist?( guess )
187
- end
188
- return nil
189
- end
190
-
191
- #
192
- # Make the manifest for packing
193
- #
194
- def make_manifest( file_list )
195
- manifest = []
196
- prefix_path = ::Pathname.new( options[:strip_prefix] )
197
- file_list.each do |f|
198
- file_path = ::Pathname.new( File.expand_path( f ) )
199
- m = ::OpenStruct.new
200
- # if it is a directory then grab all the .rb files from it
201
- if File.directory?( file_path ) then
202
- manifest.concat( make_manifest( Dir.glob( File.join( f, "**", "*.rb" ) ) ) )
203
- next
204
- elsif File.readable?( file_path ) then
205
- m.require_path = file_path.relative_path_from( prefix_path )
206
- m.file_path = file_path.realpath.to_s
207
- elsif lp = full_path_of( f ) then
208
- m.require_path = f
209
- m.file_path = lp
210
- else
211
- STDERR.puts "Unable to add #{f} to the manifest, cannot find the file on disk"
212
- next
213
- end
214
- # Make sure that we can handle files without the .rb extension
215
- # if we have to. This means bin/foo works as a require path
216
- # without requiring bin/foo to actually be bin/foo.rb
217
- m.require_path = m.require_path.to_s.sub(/\.rb\Z/,'')
218
- manifest << m
219
- end
220
- return manifest
221
- end
222
-
223
- #
224
- # Given a list of files pack them into the associated database and table.
225
- #
226
- def pack( file_list )
227
- manifest = make_manifest( file_list )
228
- pack_files( manifest )
229
- end
230
- end
231
- end
@@ -1,151 +0,0 @@
1
- require 'amalgalite'
2
- require 'pathname'
3
- require 'zlib'
4
- require 'amalgalite/packer'
5
-
6
- module Amalgalite
7
- #
8
- # Requires encapsulates requiring items from the database
9
- #
10
- class Requires
11
- class << self
12
- def load_path_db_connections
13
- @load_path_db_connections ||= {}
14
- end
15
-
16
- def load_path
17
- @load_path ||= []
18
- end
19
-
20
- #
21
- # Allocate a database connection to the given filename. For
22
- # file databases, this means giving the same connection
23
- # back if you ask for a connection to the same file.
24
- # For in-memory databases, you get a new one each time.
25
- #
26
- def db_connection_to( dbfile_name )
27
- if dbfile_name == ":memory:"
28
- return ::Amalgalite::Database.new( dbfile_name )
29
- else
30
- unless connection = load_path_db_connections[ dbfile_name ]
31
- connection = ::Amalgalite::Database.new( dbfile_name )
32
- load_path_db_connections[dbfile_name] = connection
33
- end
34
- return connection
35
- end
36
- end
37
-
38
- #
39
- # Setting a class level variable as a flag to know what we are currently
40
- # in the middle of requiring
41
- #
42
- def requiring
43
- @requiring ||= []
44
- end
45
-
46
- def require( filename )
47
- if load_path.empty? then
48
- raise ::LoadError, "Amalgalite load path is empty -- #{filename}"
49
- elsif $LOADED_FEATURES.include?( filename ) then
50
- return false
51
- elsif Requires.requiring.include?( filename ) then
52
- return false
53
- else
54
- Requires.requiring << filename
55
- load_path.each do |lp|
56
- if lp.require( filename ) then
57
- Requires.requiring.delete( filename )
58
- return true
59
- end
60
- end
61
- Requires.requiring.delete( filename )
62
- raise ::LoadError, "amalgalite has no such file to load -- #{filename}"
63
- end
64
- end
65
- end
66
-
67
- attr_reader :dbfile_name
68
- attr_reader :table_name
69
- attr_reader :filename_column
70
- attr_reader :contents_column
71
- attr_reader :compressed_column
72
- attr_reader :db_connection
73
-
74
- def initialize( opts = {} )
75
- @dbfile_name = opts[:dbfile_name] || Bootstrap::DEFAULT_DB
76
- @table_name = opts[:table_name] || Bootstrap::DEFAULT_TABLE
77
- @filename_column = opts[:filename_column] || Bootstrap::DEFAULT_FILENAME_COLUMN
78
- @contents_column = opts[:contents_column] || Bootstrap::DEFAULT_CONTENTS_COLUMN
79
- @compressed_column = opts[:compressed_column] || Bootstrap::DEFAULT_COMPRESSED_COLUMN
80
- @db_connection = Requires.db_connection_to( dbfile_name )
81
- Requires.load_path << self
82
- end
83
-
84
- #
85
- # return the sql to find the file contents for a file in this requires
86
- #
87
- def sql
88
- @sql ||= "SELECT #{filename_column}, #{compressed_column}, #{contents_column} FROM #{table_name} WHERE #{filename_column} = ?"
89
- end
90
-
91
- #
92
- # load a file in this database table. This will check and see if the
93
- # file is already required. If it isn't it will select the contents
94
- # associated with the row identified by the filename and eval those contents
95
- # within the context of TOPLEVEL_BINDING. The filename is then appended to
96
- # $LOADED_FEATURES.
97
- #
98
- # if the file was required then true is returned, otherwise false
99
- #
100
- def require( filename )
101
- if $LOADED_FEATURES.include?( filename ) then
102
- return false
103
- else
104
- begin
105
- filename = filename.gsub(/\.rb\Z/,'')
106
-
107
- contents = file_contents(filename)
108
-
109
- if contents
110
- eval( contents, TOPLEVEL_BINDING, filename )
111
- $LOADED_FEATURES << filename
112
- return true
113
- else
114
- return false
115
- end
116
- rescue => e
117
- raise ::LoadError, "Failure loading #{filename} from #{dbfile_name} : #{e}"
118
- end
119
- end
120
- end
121
-
122
- #
123
- # Return the contents of the named file.
124
- #
125
- def file_contents(filename)
126
- rows = db_connection.execute(sql, filename)
127
- if rows.size > 0 then
128
- row = rows.first
129
-
130
- contents = row[contents_column].to_s
131
- if row[compressed_column] then
132
- contents = ::Amalgalite::Packer.gunzip( contents )
133
- end
134
-
135
- return contents
136
- else
137
- return nil
138
- end
139
- end
140
-
141
-
142
- #
143
- # Import an SQL dump into the fake file system.
144
- #
145
- def import(sql)
146
- db_connection.import(sql)
147
- end
148
-
149
- end
150
- end
151
- require 'amalgalite/core_ext/kernel/require'