Module: Archive::Tar::Minitar
- Defined in:
- lib/shoes/minitar.rb
Overview
Archive::Tar::Minitar 0.5.1
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 Fern?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.1. 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 Fern?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.
Defined Under Namespace
Classes: BlockRequired, ClosedStream, FileNameTooLong, Input, NonSeekableStream, Output, Reader, UnexpectedEOF, Writer
Constant Summary
- VERSION =
"0.5.1"
Class Method Summary (collapse)
-
+ (Boolean) dir?(path)
Tests if path refers to a directory.
-
+ (Object) open(dest, mode = "r", &block)
A convenience method for wrapping Archive::Tar::Minitar::Input.open (mode r) and Archive::Tar::Minitar::Output.open (mode w).
-
+ (Object) pack(src, dest, recurse_dirs = true, &block)
A convenience method to pack files specified by src into dest.
-
+ (Object) pack_file(entry, outputter)
A convenience method to packs the file provided.
-
+ (Object) unpack(src, dest, files = [], &block)
A convenience method to unpack files from src into the directory specified by dest.
Class Method Details
+ (Boolean) dir?(path)
Tests if path refers to a directory. Fixes an apparently corrupted stat() call on Windows.
836 837 838 |
# File 'lib/shoes/minitar.rb', line 836 def dir?(path) File.directory?((path[-1] == ?/) ? path : "#{path}/") end |
+ (Object) open(dest, mode = "r", &block)
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.
843 844 845 846 847 848 849 850 851 852 |
# File 'lib/shoes/minitar.rb', line 843 def open(dest, mode = "r", &block) case mode when "r" Input.open(dest, &block) when "w" Output.open(dest, &block) else raise "Unknown open mode for Archive::Tar::Minitar.open." end end |
+ (Object) pack(src, dest, recurse_dirs = true, &block)
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.
948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 |
# File 'lib/shoes/minitar.rb', line 948 def pack(src, dest, recurse_dirs = true, &block) Output.open(dest) do |outp| if src.kind_of?(Array) src.each do |entry| pack_file(entry, outp, &block) if dir?(entry) and recurse_dirs Dir["#{entry}/**/**"].each do |ee| pack_file(ee, outp, &block) end end end else Find.find(src) do |entry| pack_file(entry, outp, &block) end end end end |
+ (Object) pack_file(entry, outputter)
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. |
889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 |
# File 'lib/shoes/minitar.rb', line 889 def pack_file(entry, outputter) #:yields action, name, stats: outputter = outputter.tar if outputter.kind_of?(Archive::Tar::Minitar::Output) stats = {} if entry.kind_of?(Hash) name = entry[:name] entry.each { |kk, vv| stats[kk] = vv unless vv.nil? } else name = entry end name = name.sub(%r{\./}, '') stat = File.stat(name) stats[:mode] ||= stat.mode stats[:mtime] ||= stat.mtime stats[:size] = stat.size if name == "sh-install" # an ugly shoes-specific hack, to stats[:mode] = 0755 # get the file to be 0755 on windows end if RUBY_PLATFORM =~ /win32/ stats[:uid] = nil stats[:gid] = nil else stats[:uid] ||= stat.uid stats[:gid] ||= stat.gid end case when File.file?(name) outputter.add_file_simple(name, stats) do |os| stats[:current] = 0 yield :file_start, name, stats if block_given? File.open(name, "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 when dir?(name) yield :dir, name, stats if block_given? outputter.mkdir(name, stats) else raise "Don't yet know how to pack this type of file." end end |
+ (Object) unpack(src, dest, files = [], &block)
A convenience method to unpack files from src into the directory specified by dest. Only those files named explicitly in files will be extracted.
970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 |
# File 'lib/shoes/minitar.rb', line 970 def unpack(src, dest, files = [], &block) Input.open(src) do |inp| if File.exist?(dest) and (not dir?(dest)) raise "Can't unpack to a non-directory." elsif not File.exist?(dest) FileUtils.mkdir_p(dest) end inp.each do |entry| if files.empty? or files.include?(entry.full_name) inp.extract_entry(dest, entry, &block) end end end end |