module Archive::Tar::Minitar
Archive::Tar::Minitar
0.5.2¶ ↑
Archive::Tar::Minitar
is a pure-Ruby library and command-line utility that provides the ability to deal with POSIX tar(1) archive files. The implementation is based heavily on Mauricio Ferna'ndez's implementation in rpa-base, but has been reorganised to promote reuse in other projects.
This tar class performs a subset of all tar (POSIX tape archive) operations. We can only deal with typeflags 0, 1, 2, and 5 (see Archive::Tar::PosixHeader
). All other typeflags will be treated as normal files.
- NOTE:
-
support for typeflags 1 and 2 is not yet implemented in this version.
This release is version 0.5.2. The library can only handle files and directories at this point. A future version will be expanded to handle symbolic links and hard links in a portable manner. The command line utility, minitar, can only create archives, extract from archives, and list archive contents.
Synopsis¶ ↑
Using this library is easy. The simplest case is:
require 'zlib' require 'archive/tar/minitar' include Archive::Tar # Packs everything that matches Find.find('tests') File.open('test.tar', 'wb') { |tar| Minitar.pack('tests', tar) } # Unpacks 'test.tar' to 'x', creating 'x' if necessary. Minitar.unpack('test.tar', 'x')
A gzipped tar can be written with:
tgz = Zlib::GzipWriter.new(File.open('test.tgz', 'wb')) # Warning: tgz will be closed! Minitar.pack('tests', tgz) tgz = Zlib::GzipReader.new(File.open('test.tgz', 'rb')) # Warning: tgz will be closed! Minitar.unpack(tgz, 'x')
As the case above shows, one need not write to a file. However, it will sometimes require that one dive a little deeper into the API, as in the case of StringIO objects. Note that I'm not providing a block with Minitar::Output
, as Minitar::Output#close
automatically closes both the Output
object and the wrapped data stream object.
begin sgz = Zlib::GzipWriter.new(StringIO.new("")) tar = Output.new(sgz) Find.find('tests') do |entry| Minitar.pack_file(entry, tar) end ensure # Closes both tar and sgz. tar.close end
Copyright¶ ↑
Copyright 2004 Mauricio Julio Ferna'ndez Pradier and Austin Ziegler
This program is based on and incorporates parts of RPA::Package from rpa-base (lib/rpa/package.rb and lib/rpa/util.rb) by Mauricio and has been adapted to be more generic by Austin.
'minitar' contains an adaptation of Ruby/ProgressBar by Satoru Takabayashi <satoru@namazu.org>, copyright 2001 - 2004.
This program is free software. It may be redistributed and/or modified under the terms of the GPL version 2 (or later) or Ruby's licence.
Constants
- VERSION
Public Class Methods
Tests if path
refers to a directory. Fixes an apparently corrupted stat()
call on Windows.
# File lib/archive/tar/minitar.rb 832 def dir?(path) 833 File.directory?((path[-1] == ?/) ? path : "#{path}/") 834 end
A convenience method for wrapping Archive::Tar::Minitar::Input.open
(mode r
) and Archive::Tar::Minitar::Output.open
(mode w
). No other modes are currently supported.
# File lib/archive/tar/minitar.rb 839 def open(dest, mode = "r", &block) 840 case mode 841 when "r" 842 Input.open(dest, &block) 843 when "w" 844 Output.open(dest, &block) 845 else 846 raise "Unknown open mode for Archive::Tar::Minitar.open." 847 end 848 end
A convenience method to pack files specified by src
into dest
. If src
is an Array, then each file detailed therein will be packed into the resulting Archive::Tar::Minitar::Output
stream; if recurse_dirs
is true, then directories will be recursed.
If src
is an Array, it will be treated as the argument to Find.find; all files matching will be packed.
# File lib/archive/tar/minitar.rb 941 def pack(src, dest, recurse_dirs = true, &block) 942 Output.open(dest) do |outp| 943 if src.kind_of?(Array) 944 src.each do |entry| 945 pack_file(entry, outp, &block) 946 if dir?(entry) and recurse_dirs 947 Dir["#{entry}/**/**"].each do |ee| 948 pack_file(ee, outp, &block) 949 end 950 end 951 end 952 else 953 Find.find(src) do |entry| 954 pack_file(entry, outp, &block) 955 end 956 end 957 end 958 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 File#stat(entry)
or a Hash with the fields:
:name
-
The filename to be packed into the tarchive. REQUIRED.
:mode
-
The mode to be applied.
:uid
-
The user owner of the file. (Ignored on Windows.)
:gid
-
The group owner of the file. (Ignored on Windows.)
:mtime
-
The modification Time of the file.
During packing, if a block is provided, pack_file yields an action
Symol, the full name of the file being packed, and a Hash of statistical information, just as with Archive::Tar::Minitar::Input#extract_entry
.
The action
will be one of:
:dir
-
The
entry
is a directory. :file_start
-
The
entry
is a file; the extract of the file is just beginning. :file_progress
-
Yielded every 4096 bytes during the extract of the
entry
. :file_done
-
Yielded when the
entry
is completed.
The stats
hash contains the following keys:
:current
-
The current total number of bytes read in the
entry
. :currinc
-
The current number of bytes read in this read cycle.
:name
-
The filename to be packed into the tarchive. REQUIRED.
:mode
-
The mode to be applied.
:uid
-
The user owner of the file. (
nil
on Windows.) :gid
-
The group owner of the file. (
nil
on Windows.) :mtime
-
The modification Time of the file.
# File lib/archive/tar/minitar.rb 885 def pack_file(entry, outputter) #:yields action, name, stats: 886 outputter = outputter.tar if outputter.kind_of?(Archive::Tar::Minitar::Output) 887 888 stats = {} 889 890 if entry.kind_of?(Hash) 891 name = entry[:name] 892 893 entry.each { |kk, vv| stats[kk] = vv unless vv.nil? } 894 else 895 name = entry 896 end 897 898 name = name.sub(%r{\./}, '') 899 stat = File.stat(name) 900 stats[:mode] ||= stat.mode 901 stats[:mtime] ||= stat.mtime 902 stats[:size] = stat.size 903 904 if RUBY_PLATFORM =~ /win32/ 905 stats[:uid] = nil 906 stats[:gid] = nil 907 else 908 stats[:uid] ||= stat.uid 909 stats[:gid] ||= stat.gid 910 end 911 912 case 913 when File.file?(name) 914 outputter.add_file_simple(name, stats) do |os| 915 stats[:current] = 0 916 yield :file_start, name, stats if block_given? 917 File.open(name, "rb") do |ff| 918 until ff.eof? 919 stats[:currinc] = os.write(ff.read(4096)) 920 stats[:current] += stats[:currinc] 921 yield :file_progress, name, stats if block_given? 922 end 923 end 924 yield :file_done, name, stats if block_given? 925 end 926 when dir?(name) 927 yield :dir, name, stats if block_given? 928 outputter.mkdir(name, stats) 929 else 930 raise "Don't yet know how to pack this type of file." 931 end 932 end
A convenience method to unpack files from src
into the directory specified by dest
. Only those files named explicitly in files
will be extracted.
# File lib/archive/tar/minitar.rb 963 def unpack(src, dest, files = [], &block) 964 Input.open(src) do |inp| 965 if File.exist?(dest) and (not dir?(dest)) 966 raise "Can't unpack to a non-directory." 967 elsif not File.exist?(dest) 968 FileUtils.mkdir_p(dest) 969 end 970 971 inp.each do |entry| 972 if files.empty? or files.include?(entry.full_name) 973 inp.extract_entry(dest, entry, &block) 974 end 975 end 976 end 977 end