Module: Archive::Tar::Minitar
- Defined in:
- lib/folio/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�dez’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�dez 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.1"
Class Method Summary collapse
-
.dir?(path) ⇒ Boolean
Tests if
pathrefers 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
srcintodest. -
.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
srcinto 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.
914 915 916 |
# File 'lib/folio/minitar.rb', line 914 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.
921 922 923 924 925 926 927 928 929 930 |
# File 'lib/folio/minitar.rb', line 921 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.
1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 |
# File 'lib/folio/minitar.rb', line 1023 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
entryis a directory. :file_start-
The
entryis 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
entryis 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. (
nilon Windows.) :gid-
The group owner of the file. (
nilon Windows.) :mtime-
The modification Time of the file.
967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 |
# File 'lib/folio/minitar.rb', line 967 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.
1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 |
# File 'lib/folio/minitar.rb', line 1045 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 |