Class: Amalgalite::Packer

Inherits:
Object
  • Object
show all
Defined in:
lib/amalgalite/packer.rb

Overview

Pack items into an amalgalite database.

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(options = {}) ⇒ Packer

Create a new packer instance with the list of items to pack and all the options



99
100
101
102
# File 'lib/amalgalite/packer.rb', line 99

def initialize(  options = {} )
  @options = Packer.default_options.merge( options )
  @dbfile  = @options[:dbfile] || Requires::Bootstrap::DEFAULT_DB
end

Instance Attribute Details

#dbfileObject (readonly)

Returns the value of attribute dbfile.



13
14
15
# File 'lib/amalgalite/packer.rb', line 13

def dbfile
  @dbfile
end

#optionsObject (readonly)

Returns the value of attribute options.



14
15
16
# File 'lib/amalgalite/packer.rb', line 14

def options
  @options
end

#packing_listObject (readonly)

Returns the value of attribute packing_list.



12
13
14
# File 'lib/amalgalite/packer.rb', line 12

def packing_list
  @packing_list
end

Class Method Details

.amalgalite_require_orderObject

return the files in their dependency order for use for packing into a database



53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
# File 'lib/amalgalite/packer.rb', line 53

def amalgalite_require_order
  @require_order ||= %w[
    amalgalite.rb
    amalgalite/sqlite3/database/function.rb
    amalgalite/aggregate.rb
    amalgalite/blob.rb
    amalgalite/boolean.rb
    amalgalite/busy_timeout.rb
    amalgalite/column.rb
    amalgalite/statement.rb
    amalgalite/trace_tap.rb
    amalgalite/profile_tap.rb
    amalgalite/type_map.rb
    amalgalite/type_maps/storage_map.rb
    amalgalite/type_maps/text_map.rb
    amalgalite/type_maps/default_map.rb
    amalgalite/function.rb
    amalgalite/progress_handler.rb
    amalgalite/csv_table_importer.rb
    amalgalite/database.rb
    amalgalite/index.rb
    amalgalite/memory_database.rb
    amalgalite/paths.rb
    amalgalite/table.rb
    amalgalite/view.rb
    amalgalite/schema.rb
    amalgalite/version.rb
    amalgalite/sqlite3/version.rb
    amalgalite/sqlite3/constants.rb
    amalgalite/sqlite3/status.rb
    amalgalite/sqlite3/database/status.rb
    amalgalite/sqlite3.rb
    amalgalite/taps/io.rb
    amalgalite/taps/console.rb
    amalgalite/taps.rb
    amalgalite/packer.rb
    amalgalite/core_ext/kernel/require.rb
    amalgalite/requires.rb
  ]
end

.default_optionsObject



17
18
19
20
21
22
23
24
25
26
27
# File 'lib/amalgalite/packer.rb', line 17

def default_options
  {
    :table_name        => Requires::Bootstrap::DEFAULT_TABLE,
    :filename_column   => Requires::Bootstrap::DEFAULT_FILENAME_COLUMN,
    :contents_column   => Requires::Bootstrap::DEFAULT_CONTENTS_COLUMN,
    :compressed_column => Requires::Bootstrap::DEFAULT_COMPRESSED_COLUMN,
    :strip_prefix      => Dir.pwd,
    :compressed        => false,
    :verbose           => false,
  }
end

.gunzip(data) ⇒ Object

uncompress gzip data



43
44
45
46
# File 'lib/amalgalite/packer.rb', line 43

def gunzip( data )
  data = StringIO.new( data )
  Zlib::GzipReader.new( data ).read
end

.gzip(data) ⇒ Object

compress data



32
33
34
35
36
37
38
# File 'lib/amalgalite/packer.rb', line 32

def gzip( data )
  zipped = StringIO.new
  Zlib::GzipWriter.wrap( zipped ) do |io|
    io.write( data )
  end
  return zipped.string
end

Instance Method Details

#check_db(db) ⇒ Object

Make sure that the dbfile exists and has the appropriate schema.



121
122
123
124
125
126
127
128
129
130
131
132
133
# File 'lib/amalgalite/packer.rb', line 121

def check_db( db )
  if db.schema.tables[ options[:table_name] ] and options[:drop_table] then
    STDERR.puts "Dropping table #{options[:table_name]}" if options[:verbose]
    db.execute("DROP TABLE #{options[:table_name]}")
    db.reload_schema!
  end

  unless db.schema.tables[ options[:table_name] ]
    db.execute( create_table_sql )
    db.reload_schema!
  end

end

#create_table_sqlObject

The SQL to create the table for storing ruby code



107
108
109
110
111
112
113
114
115
116
# File 'lib/amalgalite/packer.rb', line 107

def create_table_sql
  <<-create
  CREATE TABLE #{options[:table_name]} (
  id                   INTEGER PRIMARY KEY AUTOINCREMENT,
  #{options[:filename_column]}   TEXT UNIQUE,
  #{options[:compressed_column]} BOOLEAN,
  #{options[:contents_column]}   BLOB
  );
  create
end

#full_path_of(rb_file) ⇒ Object

given a file, see if it can be found in the ruby load path, if so, return that full path



183
184
185
186
187
188
189
# File 'lib/amalgalite/packer.rb', line 183

def full_path_of( rb_file )
  $LOAD_PATH.each do |load_path|
    guess = File.expand_path( File.join( load_path, rb_file ) )
    return guess if File.exist?( guess )
  end
  return nil
end

#make_manifest(file_list) ⇒ Object

Make the manifest for packing



194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
# File 'lib/amalgalite/packer.rb', line 194

def make_manifest( file_list )
  manifest = []
  prefix_path = ::Pathname.new( options[:strip_prefix] )
  file_list.each do |f|
    file_path = ::Pathname.new( File.expand_path( f ) )
    m = ::OpenStruct.new
    # if it is a directory then grab all the .rb files from it
    if File.directory?( file_path ) then
      manifest.concat( make_manifest( Dir.glob( File.join( f, "**", "*.rb" ) ) ) )
      next
    elsif File.readable?( file_path ) then
      m.require_path = file_path.relative_path_from( prefix_path )
      m.file_path    = file_path.realpath.to_s
    elsif lp = full_path_of( f ) then
      m.require_path = f
      m.file_path    = lp
    else
      STDERR.puts "Unable to add #{f} to the manifest, cannot find the file on disk"
      next
    end
    # Make sure that we can handle files without the .rb extension
    # if we have to. This means bin/foo works as a require path
    # without requiring bin/foo to actually be bin/foo.rb
    m.require_path = m.require_path.to_s.sub(/\.rb\Z/,'')
    manifest << m
  end
  return manifest
end

#pack(file_list) ⇒ Object

Given a list of files pack them into the associated database and table.



226
227
228
229
# File 'lib/amalgalite/packer.rb', line 226

def pack( file_list )
  manifest = make_manifest( file_list )
  pack_files( manifest )
end

#pack_files(manifest) ⇒ Object

Stores all the .rb files in the list into the given database. The prefix is the file system path to remove from the front of the path on each file

manifest is an array of OpenStructs.



142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
# File 'lib/amalgalite/packer.rb', line 142

def pack_files( manifest )
  db = Amalgalite::Database.new( dbfile )
  check_db( db )
  max_width = manifest.collect{ |m| m.require_path.length }.sort.last
  contents_column = db.schema.tables[ options[:table_name] ].columns[ options[:contents_column] ]
  db.transaction do |trans|
    manifest.each do |file_info|
      msg  = "  -> #{file_info.require_path.ljust( max_width )} : "
      begin
        if options[:merge] then
          trans.execute( "DELETE FROM #{options[:table_name]} WHERE #{options[:filename_column]} = ?", file_info.require_path )
        end

        trans.prepare("INSERT INTO #{options[:table_name]}(#{options[:filename_column]}, #{options[:compressed_column]}, #{options[:contents_column]}) VALUES( $filename, $compressed, $contents)") do |stmt|
          contents = IO.readlines( file_info.file_path )
          if options[:self] then
            contents.each { |l| l.gsub!( /^(\s*require .*)$/m, "# commented out by #{self.class.name} \\1") }
          end
          contents = contents.join

          if options[:compressed] then
            contents = Packer.gzip( contents )
          end
          content_io = StringIO.new( contents )
          stmt.execute( "$filename"   => file_info.require_path,
                        "$contents"   => Amalgalite::Blob.new( :io => content_io,
                                                               :column => contents_column ),
                        "$compressed" => options[:compressed] )
          STDERR.puts "#{msg} stored #{file_info.file_path}" if options[:verbose]
        end
      rescue => e
        STDERR.puts "#{msg} error #{e}"
      end
    end
  end
end