Module: Archive::Tar::Minitar
- Defined in:
- lib/amp/dependencies/minitar.rb
Overview
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 <[email protected]>, 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 collapse
- VERSION =
"0.5.2"
Class Method Summary collapse
-
.dir?(path) ⇒ Boolean
Tests if
path
refers to a directory. -
.open(dest, mode = "r", &block) ⇒ Object
A convenience method for wrapping Archive::Tar::Minitar::Input.open (mode
r
) and Archive::Tar::Minitar::Output.open (modew
). -
.pack(src, dest, recurse_dirs = true, &block) ⇒ Object
A convenience method to pack files specified by
src
intodest
. -
.pack_file(entry, outputter) ⇒ Object
A convenience method to packs the file provided.
-
.unpack(src, dest, files = [], &block) ⇒ Object
A convenience method to unpack files from
src
into the directory specified bydest
.
Class Method Details
.dir?(path) ⇒ Boolean
Tests if path
refers to a directory. Fixes an apparently corrupted stat()
call on Windows.
832 833 834 |
# File 'lib/amp/dependencies/minitar.rb', line 832 def dir?(path) File.directory?((path[-1] == ?/) ? path : "#{path}/") end |
.open(dest, mode = "r", &block) ⇒ Object
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.
839 840 841 842 843 844 845 846 847 848 |
# File 'lib/amp/dependencies/minitar.rb', line 839 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 |
.pack(src, dest, recurse_dirs = true, &block) ⇒ Object
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.
941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 |
# File 'lib/amp/dependencies/minitar.rb', line 941 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 |
.pack_file(entry, outputter) ⇒ Object
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.
885 886 887 888 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 |
# File 'lib/amp/dependencies/minitar.rb', line 885 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 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 |
.unpack(src, dest, files = [], &block) ⇒ Object
A convenience method to unpack files from src
into the directory specified by dest
. Only those files named explicitly in files
will be extracted.
963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 |
# File 'lib/amp/dependencies/minitar.rb', line 963 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 |