The method 'pack_file' only works on real files (on disk). I implemented a method (which is very similar to pack_file)
that allows the creation of a tar archive from data in memory. To use it to create a .tgz file from data in memory:
require 'zlib'
require 'archive/tar/minitar'
file_names = ['wiley/dorky1', 'dorky2', 'an_empty_dir']
file_data_strings = ['my data', 'my data also', nil]
tgz = Zlib::GzipWriter.new(File.open('dorky_tar.tgz', 'wb'))
Archive::Tar::Minitar::Output.open(tgz) do |outp|
file_names.zip(file_data_strings) do |name, data|
Archive::Tar::Minitar.pack_as_file(name, data, outp)
end
end
Index: minitar/trunk/lib/archive/tar/minitar.rb
--- minitar/trunk/lib/archive/tar/minitar.rb (revision 215)
+++ minitar/trunk/lib/archive/tar/minitar.rb (working copy)
@@ -12,6 +12,8 @@
# $Id$
#++
+require 'stringio'
+
module Archive; end
module Archive::Tar; end
@@ -847,6 +849,64 @@
end
end
+
+ # entry may be a string (the name), or it may be a hash specifying the
+ # following (showing defaults below):
+ # <tt>:name</tt> *REQUIRED*
+ # <tt>:mode</tt> 33188 (rw-r--r--) for files, 16877 (rwxr-xr-x) for dirs
+ # (0O100644) (0O40755)
+ # <tt>:uid</tt> nil
+ # <tt>:gid</tt> nil
+ # <tt>:mtime</tt> Time.now
+ #
+ # if data == nil, then it will be created as a directory (use an empty
+ # string for a normal empty file)
+ # note that data should be something that can be opened by StringIO
+ def pack_as_file(entry, data, outputter) #:yields action, name, stats:
+ outputter = outputter.tar if outputter.kind_of?(Archive::Tar::Minitar::Output)
+
+ stats = {}
+ stats[:uid] = nil
+ stats[:gid] = nil
+ stats[:mtime] = Time.now
+
+ if data.nil?
+ # a directory
+ stats[:size] = 4096 # is this OK???
+ stats[:mode] = 16877 # rwxr-xr-x
+ else
+ stats[:size] = data.size
+ stats[:mode] = 33188 # rw-r--r--
+ end
+
+ if entry.kind_of?(Hash)
+ name = entry[:name]
+
+ entry.each { |kk, vv| stats[kk] = vv unless vv.nil? }
+ else
+ name = entry
+ end
+
+ if data.nil? # a directory
+ yield :dir, name, stats if block_given?
+ outputter.mkdir(name, stats)
+ else # a file
+ outputter.add_file_simple(name, stats) do |os|
+ stats[:current] = 0
+ yield :file_start, name, stats if block_given?
+ StringIO.open(data, "rb") do |ff|
+ until ff.eof?
+ stats[:currinc] = os.write(ff.read(4096))
+ stats[:current] += stats[:currinc]
+ yield :file_progress, name, stats if block_given?
+ end
+ end
+ yield :file_done, name, stats if block_given?
+ end
+ end
+ end
+
+
# A convenience method to packs the file provided. +entry+ may either be
# a filename (in which case various values for the file (see below) will
# be obtained from <tt>File#stat(entry)</tt> or a Hash with the fields:
Originally submitted by John Prince (http://rubyforge.org/users/jtprince).
The method 'pack_file' only works on real files (on disk). I implemented a method (which is very similar to pack_file) that allows the creation of a tar archive from data in memory. To use it to create a .tgz file from data in memory:
Index: minitar/trunk/lib/archive/tar/minitar.rb