diff options
author | Austin Ziegler <austin@rubyforge.org> | 2007-02-05 04:09:51 +0000 |
---|---|---|
committer | Austin Ziegler <austin@rubyforge.org> | 2007-02-05 04:09:51 +0000 |
commit | 498bb3c674bf011a9b4d0ba6bb4a84a2a2c925b6 (patch) | |
tree | 26ef5bb238e248eeab2c742a0a24a3f8c24db59b | |
parent | 0b8fa777cab062609fa05952d1f7b9660e2e9cff (diff) | |
download | diff-lcs-498bb3c674bf011a9b4d0ba6bb4a84a2a2c925b6.tar.gz |
Finishing cleanup.
19 files changed, 0 insertions, 5729 deletions
diff --git a/tags/version_0_5_0/minitar/ChangeLog b/tags/version_0_5_0/minitar/ChangeLog deleted file mode 100644 index baf5d74..0000000 --- a/tags/version_0_5_0/minitar/ChangeLog +++ /dev/null @@ -1,8 +0,0 @@ -Revision history for Ruby library Archive::Tar::Minitar. Unless explicitly -noted otherwise, all changes are produced by Austin Ziegler -<minitar@halostatue.ca>. - -== Archive::Tar::Minitar -* Initial release. Does files and directories. Command does create, extract, -* and list. - diff --git a/tags/version_0_5_0/minitar/Install b/tags/version_0_5_0/minitar/Install deleted file mode 100644 index ef1af1a..0000000 --- a/tags/version_0_5_0/minitar/Install +++ /dev/null @@ -1,6 +0,0 @@ -Installing this package is as simple as: - -% ruby install.rb - -Alternatively, you can use the RubyGem version of Archive::Tar::Minitar -available as archive-tar-minitar-0.5.0.gem from the usual sources. diff --git a/tags/version_0_5_0/minitar/README b/tags/version_0_5_0/minitar/README deleted file mode 100644 index 6b75a1a..0000000 --- a/tags/version_0_5_0/minitar/README +++ /dev/null @@ -1,67 +0,0 @@ -Archive::Tar::Minitar README -============================ -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 release is version 0.5.0. 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. - -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. -# -# $Id$ diff --git a/tags/version_0_5_0/minitar/bin/minitar b/tags/version_0_5_0/minitar/bin/minitar deleted file mode 100644 index f887e48..0000000 --- a/tags/version_0_5_0/minitar/bin/minitar +++ /dev/null @@ -1,26 +0,0 @@ -#!/usr/bin/env ruby -#-- -# Archive::Tar::Minitar 0.5.0 -# 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. -# -# It is licensed under the GNU General Public Licence or Ruby's licence. -# -# $Id$ -#++ - - # 1) Try to load Archive::Tar::Minitar from the gem. - # 2) Try to load Archive::Tar::Minitar from $LOAD_PATH. -begin - require 'rubygems' - require_gem 'archive-tar-minitar' -rescue LoadError - require 'archive/tar/minitar' -end - -require 'archive/tar/minitar/command' - -exit Archive::Tar::Minitar::Command.run(ARGV) diff --git a/tags/version_0_5_0/minitar/install.rb b/tags/version_0_5_0/minitar/install.rb deleted file mode 100644 index 5772e0b..0000000 --- a/tags/version_0_5_0/minitar/install.rb +++ /dev/null @@ -1,264 +0,0 @@ -#! /usr/bin/env ruby -#-- -# Copyright 2004 Austin Ziegler <ruby-install@halostatue.ca> -# Install utility. Based on the original installation script for rdoc by the -# Pragmatic Programmers. -# -# This program is free software. It may be redistributed and/or modified under -# the terms of the GPL version 2 (or later) or the Ruby licence. -# -# Usage -# ----- -# In most cases, if you have a typical project layout, you will need to do -# absolutely nothing to make this work for you. This layout is: -# -# bin/ # executable files -- "commands" -# lib/ # the source of the library -# tests/ # unit tests -# -# The default behaviour: -# 1) Run all unit test files (ending in .rb) found in all directories under -# tests/. -# 2) Build Rdoc documentation from all files in bin/ (excluding .bat and .cmd), -# all .rb files in lib/, ./README, ./ChangeLog, and ./Install. -# 3) Build ri documentation from all files in bin/ (excluding .bat and .cmd), -# and all .rb files in lib/. This is disabled by default on Win32. -# 4) Install commands from bin/ into the Ruby bin directory. On Windows, if a -# if a corresponding batch file (.bat or .cmd) exists in the bin directory, -# it will be copied over as well. Otherwise, a batch file (always .bat) will -# be created to run the specified command. -# 5) Install all library files ending in .rb from lib/ into Ruby's -# site_lib/version directory. -# -# $Id$ -#++ - -require 'rbconfig' -require 'find' -require 'fileutils' -require 'rdoc/rdoc' -require 'optparse' -require 'ostruct' - -InstallOptions = OpenStruct.new - -def glob(list) - g = list.map { |i| Dir.glob(i) } - g.flatten! - g.compact! - g.reject! { |e| e =~ /CVS/ } - g -end - - # Set these values to what you want installed. -bins = glob(%w{bin/**/*}).reject { |e| e =~ /\.(bat|cmd)$/ } -rdoc = glob(%w{bin/**/* lib/**/*.rb README ChangeLog Install}).reject { |e| e=~ /\.(bat|cmd)$/ } -ri = glob(%w(bin/**/*.rb lib/**/*.rb)).reject { |e| e=~ /\.(bat|cmd)$/ } -libs = glob(%w{lib/**/*.rb}) -tests = glob(%w{tests/**/*.rb}) - -def do_bins(bins, target, strip = 'bin/') - bins.each do |bf| - obf = bf.gsub(/#{strip}/, '') - install_binfile(bf, obf, target) - end -end - -def do_libs(libs, strip = 'lib/') - libs.each do |lf| - olf = File.join(InstallOptions.site_dir, lf.gsub(/#{strip}/, '')) - op = File.dirname(olf) - File.makedirs(op, true) - File.chmod(0755, op) - File.install(lf, olf, 0755, true) - end -end - -## -# Prepare the file installation. -# -def prepare_installation - InstallOptions.rdoc = true - if RUBY_PLATFORM == "i386-mswin32" - InstallOptions.ri = false - else - InstallOptions.ri = true - end - InstallOptions.tests = true - - ARGV.options do |opts| - opts.banner = "Usage: #{File.basename($0)} [options]" - opts.separator "" - opts.on('--[no-]rdoc', 'Prevents the creation of RDoc output.', 'Default on.') do |onrdoc| - InstallOptions.rdoc = onrdoc - end - opts.on('--[no-]ri', 'Prevents the creation of RI output.', 'Default off on mswin32.') do |onri| - InstallOptions.ri = onri - end - opts.on('--[no-]tests', 'Prevents the execution of unit tests.', 'Default on.') do |ontest| - InstallOptions.tests = ontest - end - opts.on('--quick', 'Performs a quick installation. Only the', 'installation is done.') do |quick| - InstallOptions.rdoc = false - InstallOptions.ri = false - InstallOptions.tests = false - end - opts.on('--full', 'Performs a full installation. All', 'optional installation steps are run.') do |full| - InstallOptions.rdoc = true - InstallOptions.ri = true - InstallOptions.tests = true - end - opts.separator("") - opts.on_tail('--help', "Shows this help text.") do - $stderr.puts opts - exit - end - - opts.parse! - end - - bds = [".", ENV['TMP'], ENV['TEMP']] - - version = [Config::CONFIG["MAJOR"], Config::CONFIG["MINOR"]].join(".") - ld = File.join(Config::CONFIG["libdir"], "ruby", version) - - sd = Config::CONFIG["sitelibdir"] - if sd.nil? - sd = $:.find { |x| x =~ /site_ruby/ } - if sd.nil? - sd = File.join(ld, "site_ruby") - elsif sd !~ Regexp.quote(version) - sd = File.join(sd, version) - end - end - - if (destdir = ENV['DESTDIR']) - bd = "#{destdir}#{Config::CONFIG['bindir']}" - sd = "#{destdir}#{sd}" - bds << bd - - FileUtils.makedirs(bd) - FileUtils.makedirs(sd) - else - bds << Config::CONFIG['bindir'] - end - - InstallOptions.bin_dirs = bds.compact - InstallOptions.site_dir = sd - InstallOptions.bin_dir = bd - InstallOptions.lib_dir = ld -end - -## -# Build the rdoc documentation. Also, try to build the RI documentation. -# -def build_rdoc(files) - r = RDoc::RDoc.new - r.document(["--main", "README", "--title", "Diff::LCS -- A Diff Algorithm", - "--line-numbers"] + files) - -rescue RDoc::RDocError => e - $stderr.puts e.message -rescue Exception => e - $stderr.puts "Couldn't build RDoc documentation\n#{e.message}" -end - -def build_ri(files) - ri = RDoc::RDoc.new - ri.document(["--ri-site", "--merge"] + files) -rescue RDoc::RDocError => e - $stderr.puts e.message -rescue Exception => e - $stderr.puts "Couldn't build Ri documentation\n#{e.message}" -end - -def run_tests(test_list) - require 'test/unit/ui/console/testrunner' - $:.unshift "lib" - test_list.each do |test| - next if File.directory?(test) - require test - end - - tests = [] - ObjectSpace.each_object { |o| tests << o if o.kind_of?(Class) } - tests.delete_if { |o| !o.ancestors.include?(Test::Unit::TestCase) } - tests.delete_if { |o| o == Test::Unit::TestCase } - - tests.each { |test| Test::Unit::UI::Console::TestRunner.run(test) } - $:.shift -end - -## -# Install file(s) from ./bin to Config::CONFIG['bindir']. Patch it on the way -# to insert a #! line; on a Unix install, the command is named as expected -# (e.g., bin/rdoc becomes rdoc); the shebang line handles running it. Under -# windows, we add an '.rb' extension and let file associations do their stuff. -def install_binfile(from, op_file, target) - tmp_dir = nil - InstallOptions.bin_dirs.each do |t| - if File.directory?(t) and File.writable?(t) - tmp_dir = t - break - end - end - - fail "Cannot find a temporary directory" unless tmp_dir - tmp_file = File.join(tmp_dir, '_tmp') - ruby = File.join(Config::CONFIG['bindir'], Config::CONFIG['ruby_install_name']) - - File.open(from) do |ip| - File.open(tmp_file, "w") do |op| - ruby = File.join(Config::CONFIG['bindir'], Config::CONFIG['ruby_install_name']) - op.puts "#!#{ruby}" - op.write ip.read - end - end - - if Config::CONFIG["target_os"] =~ /win/io - installed_wrapper = false - - if File.exists?("#{from}.bat") - FileUtils.install("#{from}.bat", File.join(target, "#{op_file}.bat"), :mode => 0755, :verbose => true) - installed_wrapper = true - end - - if File.exists?("#{from}.cmd") - FileUtils.install("#{from}.cmd", File.join(target, "#{op_file}.cmd"), :mode => 0755, :verbose => true) - installed_wrapper = true - end - - if not installed_wrapper - tmp_file2 = File.join(tmp_dir, '_tmp_wrapper') - cwn = File.join(Config::CONFIG['bindir'], op_file) - cwv = CMD_WRAPPER.gsub('<ruby>', ruby.gsub(%r{/}) { "\\" }).gsub!('<command>', cwn.gsub(%r{/}) { "\\" } ) - - File.open(tmp_file2, "wb") { |cw| cw.puts cwv } - FileUtils.install(tmp_file2, File.join(target, "#{op_file}.bat"), :mode => 0755, :verbose => true) - - File.unlink(tmp_file2) - installed_wrapper = true - end - end - FileUtils.install(tmp_file, File.join(target, op_file), :mode => 0755, :verbose => true) - File.unlink(tmp_file) -end - -CMD_WRAPPER = <<-EOS -@echo off -if "%OS%"=="Windows_NT" goto WinNT -<ruby> -x "<command>" %1 %2 %3 %4 %5 %6 %7 %8 %9 -goto done -:WinNT -<ruby> -x "<command>" %* -goto done -:done -EOS - -prepare_installation - -run_tests(tests) if InstallOptions.tests -build_rdoc(rdoc) if InstallOptions.rdoc -build_ri(ri) if InstallOptions.ri -do_bins(bins, Config::CONFIG['bindir']) -do_libs(libs) diff --git a/tags/version_0_5_0/minitar/lib/archive/tar/minitar.rb b/tags/version_0_5_0/minitar/lib/archive/tar/minitar.rb deleted file mode 100644 index aace0dd..0000000 --- a/tags/version_0_5_0/minitar/lib/archive/tar/minitar.rb +++ /dev/null @@ -1,979 +0,0 @@ -#!/usr/bin/env ruby -#-- -# Archive::Tar::Minitar 0.5.0 -# 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. -# -# It is licensed under the GNU General Public Licence or Ruby's licence. -# -# $Id$ -#++ - -module Archive; end -module Archive::Tar; end - - # = Archive::Tar::PosixHeader - # Implements the POSIX tar header as a Ruby class. The structure of - # the POSIX tar header is: - # - # struct tarfile_entry_posix - # { // pack/unpack - # char name[100]; // ASCII (+ Z unless filled) a100/Z100 - # char mode[8]; // 0 padded, octal, null a8 /A8 - # char uid[8]; // ditto a8 /A8 - # char gid[8]; // ditto a8 /A8 - # char size[12]; // 0 padded, octal, null a12 /A12 - # char mtime[12]; // 0 padded, octal, null a12 /A12 - # char checksum[8]; // 0 padded, octal, null, space a8 /A8 - # char typeflag[1]; // see below a /a - # char linkname[100]; // ASCII + (Z unless filled) a100/Z100 - # char magic[6]; // "ustar\0" a6 /A6 - # char version[2]; // "00" a2 /A2 - # char uname[32]; // ASCIIZ a32 /Z32 - # char gname[32]; // ASCIIZ a32 /Z32 - # char devmajor[8]; // 0 padded, octal, null a8 /A8 - # char devminor[8]; // 0 padded, octal, null a8 /A8 - # char prefix[155]; // ASCII (+ Z unless filled) a155/Z155 - # }; - # - # The +typeflag+ may be one of the following known values: - # - # <tt>"0"</tt>:: Regular file. NULL should be treated as a synonym, for - # compatibility purposes. - # <tt>"1"</tt>:: Hard link. - # <tt>"2"</tt>:: Symbolic link. - # <tt>"3"</tt>:: Character device node. - # <tt>"4"</tt>:: Block device node. - # <tt>"5"</tt>:: Directory. - # <tt>"6"</tt>:: FIFO node. - # <tt>"7"</tt>:: Reserved. - # - # POSIX indicates that "A POSIX-compliant implementation must treat any - # unrecognized typeflag value as a regular file." -class Archive::Tar::PosixHeader - FIELDS = %w(name mode uid gid size mtime checksum typeflag linkname) + - %w(magic version uname gname devmajor devminor prefix) - - FIELDS.each { |field| attr_reader field.intern } - - HEADER_PACK_FORMAT = "a100a8a8a8a12a12a7aaa100a6a2a32a32a8a8a155" - HEADER_UNPACK_FORMAT = "Z100A8A8A8A12A12A8aZ100A6A2Z32Z32A8A8Z155" - - # Creates a new PosixHeader from a data stream. - def self.new_from_stream(stream) - data = stream.read(512) - fields = data.unpack(HEADER_UNPACK_FORMAT) - name = fields.shift - mode = fields.shift.oct - uid = fields.shift.oct - gid = fields.shift.oct - size = fields.shift.oct - mtime = fields.shift.oct - checksum = fields.shift.oct - typeflag = fields.shift - linkname = fields.shift - magic = fields.shift - version = fields.shift.oct - uname = fields.shift - gname = fields.shift - devmajor = fields.shift.oct - devminor = fields.shift.oct - prefix = fields.shift - - empty = (data == "\0" * 512) - - new(:name => name, :mode => mode, :uid => uid, :gid => gid, - :size => size, :mtime => mtime, :checksum => checksum, - :typeflag => typeflag, :magic => magic, :version => version, - :uname => uname, :gname => gname, :devmajor => devmajor, - :devminor => devminor, :prefix => prefix, :empty => empty) - end - - # Creates a new PosixHeader. A PosixHeader cannot be created unless the - # #name, #size, #prefix, and #mode are provided. - def initialize(vals) - unless vals[:name] && vals[:size] && vals[:prefix] && vals[:mode] - raise ArgumentError - end - - vals[:mtime] ||= 0 - vals[:checksum] ||= "" - vals[:typeflag] ||= "0" - vals[:magic] ||= "ustar" - vals[:version] ||= "00" - - FIELDS.each do |field| - instance_variable_set("@#{field}", vals[field.intern]) - end - @empty = vals[:empty] - end - - def empty? - @empty - end - - def to_s - update_checksum - header(@checksum) - end - - # Update the checksum field. - def update_checksum - hh = header(" " * 8) - @checksum = oct(calculate_checksum(hh), 6) - end - - private - def oct(num, len) - if num.nil? - "\0" * (len + 1) - else - "%0#{len}o" % num - end - end - - def calculate_checksum(hdr) - hdr.unpack("C*").inject { |aa, bb| aa + bb } - end - - def header(chksum) - arr = [name, oct(mode, 7), oct(uid, 7), oct(gid, 7), oct(size, 11), - oct(mtime, 11), chksum, " ", typeflag, linkname, magic, version, - uname, gname, oct(devmajor, 7), oct(devminor, 7), prefix] - str = arr.pack(HEADER_PACK_FORMAT) - str + "\0" * ((512 - str.size) % 512) - end -end - -require 'fileutils' -require 'find' - - # = Archive::Tar::Minitar 0.5.0 - # 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.0. 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. -module Archive::Tar::Minitar - VERSION = "0.5.0" - - # The exception raised when a wrapped data stream class is expected to - # respond to #rewind or #pos but does not. - class NonSeekableStream < StandardError; end - # The exception raised when a block is required for proper operation of - # the method. - class BlockRequired < ArgumentError; end - # The exception raised when operations are performed on a stream that has - # previously been closed. - class ClosedStream < StandardError; end - # The exception raised when a filename exceeds 256 bytes in length, - # the maximum supported by the standard Tar format. - class FileNameTooLong < StandardError; end - # The exception raised when a data stream ends before the amount of data - # expected in the archive's PosixHeader. - class UnexpectedEOF < StandardError; end - - # The class that writes a tar format archive to a data stream. - class Writer - # A stream wrapper that can only be written to. Any attempt to read - # from this restricted stream will result in a NameError being thrown. - class RestrictedStream - def initialize(anIO) - @io = anIO - end - - def write(data) - @io.write(data) - end - end - - # A RestrictedStream that also has a size limit. - class BoundedStream < Archive::Tar::Minitar::Writer::RestrictedStream - # The exception raised when the user attempts to write more data to - # a BoundedStream than has been allocated. - class FileOverflow < RuntimeError; end - - # The maximum number of bytes that may be written to this data - # stream. - attr_reader :limit - # The current total number of bytes written to this data stream. - attr_reader :written - - def initialize(io, limit) - @io = io - @limit = limit - @written = 0 - end - - def write(data) - raise FileOverflow if (data.size + @written) > @limit - @io.write(data) - @written += data.size - data.size - end - end - - # With no associated block, +Writer::open+ is a synonym for - # +Writer::new+. If the optional code block is given, it will be - # passed the new _writer_ as an argument and the Writer object will - # automatically be closed when the block terminates. In this instance, - # +Writer::open+ returns the value of the block. - def self.open(anIO) - writer = Writer.new(anIO) - - return writer unless block_given? - - begin - res = yield writer - ensure - writer.close - end - - res - end - - # Creates and returns a new Writer object. - def initialize(anIO) - @io = anIO - @closed = false - end - - # Adds a file to the archive as +name+. +opts+ must contain the - # following values: - # - # <tt>:mode</tt>:: The Unix file permissions mode value. - # <tt>:size</tt>:: The size, in bytes. - # - # +opts+ may contain the following values: - # - # <tt>:uid</tt>: The Unix file owner user ID number. - # <tt>:gid</tt>: The Unix file owner group ID number. - # <tt>:mtime</tt>:: The *integer* modification time value. - # - # It will not be possible to add more than <tt>opts[:size]</tt> bytes - # to the file. - def add_file_simple(name, opts = {}) # :yields BoundedStream: - raise Archive::Tar::Minitar::BlockRequired unless block_given? - raise Archive::Tar::ClosedStream if @closed - - name, prefix = split_name(name) - - header = { :name => name, :mode => opts[:mode], :mtime => opts[:mtime], - :size => opts[:size], :gid => opts[:gid], :uid => opts[:uid], - :prefix => prefix } - header = Archive::Tar::PosixHeader.new(header).to_s - @io.write(header) - - os = BoundedStream.new(@io, opts[:size]) - yield os - # FIXME: what if an exception is raised in the block? - - min_padding = opts[:size] - os.written - @io.write("\0" * min_padding) - remainder = (512 - (opts[:size] % 512)) % 512 - @io.write("\0" * remainder) - end - - # Adds a file to the archive as +name+. +opts+ must contain the - # following value: - # - # <tt>:mode</tt>:: The Unix file permissions mode value. - # - # +opts+ may contain the following values: - # - # <tt>:uid</tt>: The Unix file owner user ID number. - # <tt>:gid</tt>: The Unix file owner group ID number. - # <tt>:mtime</tt>:: The *integer* modification time value. - # - # The file's size will be determined from the amount of data written - # to the stream. - # - # For #add_file to be used, the Archive::Tar::Minitar::Writer must be - # wrapping a stream object that is seekable (e.g., it responds to - # #pos=). Otherwise, #add_file_simple must be used. - # - # +opts+ may be modified during the writing to the stream. - def add_file(name, opts = {}) # :yields RestrictedStream, +opts+: - raise Archive::Tar::Minitar::BlockRequired unless block_given? - raise Archive::Tar::Minitar::ClosedStream if @closed - raise Archive::Tar::Minitar::NonSeekableStream unless @io.respond_to?(:pos=) - - name, prefix = split_name(name) - init_pos = @io.pos - @io.write("\0" * 512) # placeholder for the header - - yield RestrictedStream.new(@io), opts - # FIXME: what if an exception is raised in the block? - - size = @io.pos - (init_pos + 512) - remainder = (512 - (size % 512)) % 512 - @io.write("\0" * remainder) - - final_pos = @io.pos - @io.pos = init_pos - - header = { :name => name, :mode => opts[:mode], :mtime => opts[:mtime], - :size => size, :gid => opts[:gid], :uid => opts[:uid], - :prefix => prefix } - header = Archive::Tar::PosixHeader.new(header).to_s - @io.write(header) - @io.pos = final_pos - end - - # Creates a directory in the tar. - def mkdir(name, opts = {}) - raise ClosedStream if @closed - name, prefix = split_name(name) - header = { :name => name, :mode => opts[:mode], :typeflag => "5", - :size => 0, :gid => opts[:gid], :uid => opts[:uid], - :mtime => opts[:mtime], :prefix => prefix } - header = Archive::Tar::PosixHeader.new(header).to_s - @io.write(header) - nil - end - - # Passes the #flush method to the wrapped stream, used for buffered - # streams. - def flush - raise ClosedStream if @closed - @io.flush if @io.respond_to?(:flush) - end - - # Closes the Writer. - def close - return if @closed - @io.write("\0" * 1024) - @closed = true - end - - private - def split_name(name) - raise FileNameTooLong if name.size > 256 - if name.size <= 100 - prefix = "" - else - parts = name.split(/\//) - newname = parts.pop - - nxt = "" - - loop do - nxt = parts.pop - break if newname.size + 1 + nxt.size > 100 - newname = "#{nxt}/#{newname}" - end - - prefix = (parts + [nxt]).join("/") - - name = newname - - raise FileNameTooLong if name.size > 100 || prefix.size > 155 - end - return name, prefix - end - end - - # The class that reads a tar format archive from a data stream. The data - # stream may be sequential or random access, but certain features only work - # with random access data streams. - class Reader - # This marks the EntryStream closed for reading without closing the - # actual data stream. - module InvalidEntryStream - def read(len = nil); raise ClosedStream; end - def getc; raise ClosedStream; end - def rewind; raise ClosedStream; end - end - - # EntryStreams are pseudo-streams on top of the main data stream. - class EntryStream - Archive::Tar::PosixHeader::FIELDS.each do |field| - attr_reader field.intern - end - - def initialize(header, anIO) - @io = anIO - @name = header.name - @mode = header.mode - @uid = header.uid - @gid = header.gid - @size = header.size - @mtime = header.mtime - @checksum = header.checksum - @typeflag = header.typeflag - @linkname = header.linkname - @magic = header.magic - @version = header.version - @uname = header.uname - @gname = header.gname - @devmajor = header.devmajor - @devminor = header.devminor - @prefix = header.prefix - @read = 0 - @orig_pos = @io.pos - end - - # Reads +len+ bytes (or all remaining data) from the entry. Returns - # +nil+ if there is no more data to read. - def read(len = nil) - return nil if @read >= @size - len ||= @size - @read - max_read = [len, @size - @read].min - ret = @io.read(max_read) - @read += ret.size - ret - end - - # Reads one byte from the entry. Returns +nil+ if there is no more data - # to read. - def getc - return nil if @read >= @size - ret = @io.getc - @read += 1 if ret - ret - end - - # Returns +true+ if the entry represents a directory. - def directory? - @typeflag == "5" - end - alias_method :directory, :directory? - - # Returns +true+ if the entry represents a plain file. - def file? - @typeflag == "0" - end - alias_method :file, :file? - - # Returns +true+ if the current read pointer is at the end of the - # EntryStream data. - def eof? - @read >= @size - end - - # Returns the current read pointer in the EntryStream. - def pos - @read - end - - # Sets the current read pointer to the beginning of the EntryStream. - def rewind - raise NonSeekableStream unless @io.respond_to?(:pos=) - @io.pos = @orig_pos - @read = 0 - end - - def bytes_read - @read - end - - # Returns the full and proper name of the entry. - def full_name - if @prefix != "" - File.join(@prefix, @name) - else - @name - end - end - - # Closes the entry. - def close - invalidate - end - - private - def invalidate - extend InvalidEntryStream - end - end - - # With no associated block, +Reader::open+ is a synonym for - # +Reader::new+. If the optional code block is given, it will be passed - # the new _writer_ as an argument and the Reader object will - # automatically be closed when the block terminates. In this instance, - # +Reader::open+ returns the value of the block. - def self.open(anIO) - reader = Reader.new(anIO) - - return reader unless block_given? - - begin - res = yield reader - ensure - reader.close - end - - res - end - - # Creates and returns a new Reader object. - def initialize(anIO) - @io = anIO - @init_pos = anIO.pos - end - - # Iterates through each entry in the data stream. - def each(&block) - each_entry(&block) - end - - # Resets the read pointer to the beginning of data stream. Do not call - # this during a #each or #each_entry iteration. This only works with - # random access data streams that respond to #rewind and #pos. - def rewind - if @init_pos == 0 - raise NonSeekableStream unless @io.respond_to?(:rewind) - @io.rewind - else - raise NonSeekableStream unless @io.respond_to?(:pos=) - @io.pos = @init_pos - end - end - - # Iterates through each entry in the data stream. - def each_entry - loop do - return if @io.eof? - - header = Archive::Tar::PosixHeader.new_from_stream(@io) - return if header.empty? - - entry = EntryStream.new(header, @io) - size = entry.size - - yield entry - - skip = (512 - (size % 512)) % 512 - - if @io.respond_to?(:seek) - # avoid reading... - @io.seek(size - entry.bytes_read, IO::SEEK_CUR) - else - pending = size - entry.bytes_read - while pending > 0 - bread = @io.read([pending, 4096].min).size - raise UnexpectedEOF if @io.eof? - pending -= bread - end - end - @io.read(skip) # discard trailing zeros - # make sure nobody can use #read, #getc or #rewind anymore - entry.close - end - end - - def close - end - end - - # Wraps a Archive::Tar::Minitar::Reader with convenience methods and - # wrapped stream management; Input only works with random access data - # streams. See Input::new for details. - class Input - include Enumerable - - # With no associated block, +Input::open+ is a synonym for - # +Input::new+. If the optional code block is given, it will be passed - # the new _writer_ as an argument and the Input object will - # automatically be closed when the block terminates. In this instance, - # +Input::open+ returns the value of the block. - def self.open(input) - stream = Input.new(input) - return stream unless block_given? - - begin - res = yield stream - ensure - stream.close - end - - res - end - - # Creates a new Input object. If +input+ is a stream object that responds - # to #read), then it will simply be wrapped. Otherwise, one will be - # created and opened using Kernel#open. When Input#close is called, the - # stream object wrapped will be closed. - def initialize(input) - if input.respond_to?(:read) - @io = input - else - @io = open(input, "rb") - end - @tarreader = Archive::Tar::Minitar::Reader.new(@io) - end - - # Iterates through each entry and rewinds to the beginning of the stream - # when finished. - def each(&block) - @tarreader.each { |entry| yield entry } - ensure - @tarreader.rewind - end - - # Extracts the current +entry+ to +destdir+. If a block is provided, it - # yields an +action+ Symbol, the full name of the file being extracted - # (+name+), and a Hash of statistical information (+stats+). - # - # The +action+ will be one of: - # <tt>:dir</tt>:: The +entry+ is a directory. - # <tt>:file_start</tt>:: The +entry+ is a file; the extract of the - # file is just beginning. - # <tt>:file_progress</tt>:: Yielded every 4096 bytes during the extract - # of the +entry+. - # <tt>:file_done</tt>:: Yielded when the +entry+ is completed. - # - # The +stats+ hash contains the following keys: - # <tt>:current</tt>:: The current total number of bytes read in the - # +entry+. - # <tt>:currinc</tt>:: The current number of bytes read in this read - # cycle. - # <tt>:entry</tt>:: The entry being extracted; this is a - # Reader::EntryStream, with all methods thereof. - def extract_entry(destdir, entry) # :yields action, name, stats: - stats = { - :current => 0, - :currinc => 0, - :entry => entry - } - - if entry.directory? - dest = File.join(destdir, entry.full_name) - - yield :dir, entry.full_name, stats if block_given? - - if Archive::Tar::Minitar.dir?(dest) - begin - FileUtils.chmod(entry.mode, dest) - rescue Exception - nil - end - else - FileUtils.mkdir_p(dest, :mode => entry.mode) - FileUtils.chmod(entry.mode, dest) - end - - fsync_dir(dest) - fsync_dir(File.join(dest, "..")) - return - else # it's a file - destdir = File.join(destdir, File.dirname(entry.full_name)) - FileUtils.mkdir_p(destdir, :mode => 0755) - - destfile = File.join(destdir, File.basename(entry.full_name)) - FileUtils.chmod(0600, destfile) rescue nil # Errno::ENOENT - - yield :file_start, entry.full_name, stats if block_given? - - File.open(destfile, "wb", entry.mode) do |os| - loop do - data = entry.read(4096) - break unless data - - stats[:currinc] = os.write(data) - stats[:current] += stats[:currinc] - - yield :file_progress, entry.full_name, stats if block_given? - end - os.fsync - end - - FileUtils.chmod(entry.mode, destfile) - fsync_dir(File.dirname(destfile)) - fsync_dir(File.join(File.dirname(destfile), "..")) - - yield :file_done, entry.full_name, stats if block_given? - end - end - - # Returns the Reader object for direct access. - def tar - @tarreader - end - - # Closes the Reader object and the wrapped data stream. - def close - @io.close - @tarreader.close - end - - private - def fsync_dir(dirname) - # make sure this hits the disc - dir = open(dirname, 'rb') - dir.fsync - rescue # ignore IOError if it's an unpatched (old) Ruby - nil - ensure - dir.close if dir rescue nil - end - end - - # Wraps a Archive::Tar::Minitar::Writer with convenience methods and - # wrapped stream management; Output only works with random access data - # streams. See Output::new for details. - class Output - # With no associated block, +Output::open+ is a synonym for - # +Output::new+. If the optional code block is given, it will be passed - # the new _writer_ as an argument and the Output object will - # automatically be closed when the block terminates. In this instance, - # +Output::open+ returns the value of the block. - def self.open(output) - stream = Output.new(output) - return stream unless block_given? - - begin - res = yield stream - ensure - stream.close - end - - res - end - - # Creates a new Output object. If +output+ is a stream object that - # responds to #read), then it will simply be wrapped. Otherwise, one will - # be created and opened using Kernel#open. When Output#close is called, - # the stream object wrapped will be closed. - def initialize(output) - if output.respond_to?(:write) - @io = output - else - @io = ::File.open(output, "wb") - end - @tarwriter = Archive::Tar::Minitar::Writer.new(@io) - end - - # Returns the Writer object for direct access. - def tar - @tarwriter - end - - # Closes the Writer object and the wrapped data stream. - def close - @tarwriter.close - @io.close - end - end - - class << self - # Tests if +path+ refers to a directory. Fixes an apparently - # corrupted <tt>stat()</tt> call on Windows. - def dir?(path) - File.directory?((path[-1] == ?/) ? path : "#{path}/") - 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. - 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 - - # 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: - # - # <tt>:name</tt>:: The filename to be packed into the tarchive. - # *REQUIRED*. - # <tt>:mode</tt>:: The mode to be applied. - # <tt>:uid</tt>:: The user owner of the file. (Ignored on Windows.) - # <tt>:gid</tt>:: The group owner of the file. (Ignored on Windows.) - # <tt>:mtime</tt>:: 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: - # <tt>:dir</tt>:: The +entry+ is a directory. - # <tt>:file_start</tt>:: The +entry+ is a file; the extract of the - # file is just beginning. - # <tt>:file_progress</tt>:: Yielded every 4096 bytes during the extract - # of the +entry+. - # <tt>:file_done</tt>:: Yielded when the +entry+ is completed. - # - # The +stats+ hash contains the following keys: - # <tt>:current</tt>:: The current total number of bytes read in the - # +entry+. - # <tt>:currinc</tt>:: The current number of bytes read in this read - # cycle. - # <tt>:name</tt>:: The filename to be packed into the tarchive. - # *REQUIRED*. - # <tt>:mode</tt>:: The mode to be applied. - # <tt>:uid</tt>:: The user owner of the file. (+nil+ on Windows.) - # <tt>:gid</tt>:: The group owner of the file. (+nil+ on Windows.) - # <tt>:mtime</tt>:: The modification Time of the file. - 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| opts[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 - - # 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. - 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 - - # A convenience method to unpack files from +src+ into the directory - # specified by +dest+. Only those files named explicitly in +files+ - # will be extracted. - 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 - end -end diff --git a/tags/version_0_5_0/minitar/lib/archive/tar/minitar/command.rb b/tags/version_0_5_0/minitar/lib/archive/tar/minitar/command.rb deleted file mode 100644 index fa65170..0000000 --- a/tags/version_0_5_0/minitar/lib/archive/tar/minitar/command.rb +++ /dev/null @@ -1,815 +0,0 @@ -#!/usr/bin/env ruby -#-- -# Archive::Tar::Baby 0.5.0 -# Copyright © 2004 Mauricio Julio Fernández Pradier and Austin Ziegler -# This is free software with ABSOLUTELY NO WARRANTY. -# -# 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. -# -# This file contains an adaptation of Ruby/ProgressBar by Satoru -# Takabayashi <satoru@namazu.org>, copyright © 2001 - 2004. -# -# It is licensed under the GNU General Public Licence or Ruby's licence. -# -# $Id$ -#++ - -require 'zlib' - -# TODO: add -# TODO: delete ??? - -require 'optparse' -require 'ostruct' -require 'fileutils' - -module Archive::Tar::Minitar::Command - class ProgressBar - VERSION = "0.8" - - attr_accessor :total - attr_accessor :title - - def initialize (title, total, out = STDERR) - @title = title - @total = total - @out = out - @bar_width = 80 - @bar_mark = "o" - @current = 0 - @previous = 0 - @is_finished = false - @start_time = Time.now - @previous_time = @start_time - @title_width = 14 - @format = "%-#{@title_width}s %3d%% %s %s" - @format_arguments = [:title, :percentage, :bar, :stat] - show - end - - private - def convert_bytes (bytes) - if bytes < 1024 - sprintf("%6dB", bytes) - elsif bytes < 1024 * 1000 # 1000kb - sprintf("%5.1fKB", bytes.to_f / 1024) - elsif bytes < 1024 * 1024 * 1000 # 1000mb - sprintf("%5.1fMB", bytes.to_f / 1024 / 1024) - else - sprintf("%5.1fGB", bytes.to_f / 1024 / 1024 / 1024) - end - end - - def transfer_rate - bytes_per_second = @current.to_f / (Time.now - @start_time) - sprintf("%s/s", convert_bytes(bytes_per_second)) - end - - def bytes - convert_bytes(@current) - end - - def format_time (t) - t = t.to_i - sec = t % 60 - min = (t / 60) % 60 - hour = t / 3600 - sprintf("%02d:%02d:%02d", hour, min, sec); - end - - # ETA stands for Estimated Time of Arrival. - def eta - if @current == 0 - "ETA: --:--:--" - else - elapsed = Time.now - @start_time - eta = elapsed * @total / @current - elapsed; - sprintf("ETA: %s", format_time(eta)) - end - end - - def elapsed - elapsed = Time.now - @start_time - sprintf("Time: %s", format_time(elapsed)) - end - - def stat - if @is_finished then elapsed else eta end - end - - def stat_for_file_transfer - if @is_finished then - sprintf("%s %s %s", bytes, transfer_rate, elapsed) - else - sprintf("%s %s %s", bytes, transfer_rate, eta) - end - end - - def eol - if @is_finished then "\n" else "\r" end - end - - def bar - len = percentage * @bar_width / 100 - sprintf("|%s%s|", @bar_mark * len, " " * (@bar_width - len)) - end - - def percentage(value = nil) - if @total.zero? - 100 - else - (value || @current) * 100 / @total - end - end - - def title - @title[0,(@title_width - 1)] + ":" - end - - def get_width - # FIXME: I don't know how portable it is. - default_width = 80 - # begin - # tiocgwinsz = 0x5413 - # data = [0, 0, 0, 0].pack("SSSS") - # if @out.ioctl(tiocgwinsz, data) >= 0 then - # rows, cols, xpixels, ypixels = data.unpack("SSSS") - # if cols >= 0 then cols else default_width end - # else - # default_width - # end - # rescue Exception - # default_width - # end - end - - def show - arguments = @format_arguments.map {|method| send(method) } - line = sprintf(@format, *arguments) - - width = get_width - if line.length == width - 1 - @out.print(line + eol) - elsif line.length >= width - @bar_width = [@bar_width - (line.length - width + 1), 0].max - if @bar_width == 0 then @out.print(line + eol) else show end - else # line.length < width - 1 - @bar_width += width - line.length + 1 - show - end - @previous_time = Time.now - end - - def show_progress - if @total.zero? - cur_percentage = 100 - prev_percentage = 0 - else - cur_percentage = (@current * 100 / @total).to_i - prev_percentage = (@previous * 100 / @total).to_i - end - - if cur_percentage > prev_percentage || - Time.now - @previous_time >= 1 || - @is_finished - show - end - end - - public - def file_transfer_mode - @format_arguments = [:title, :percentage, :bar, :stat_for_file_transfer] - end - - def format= (format) - @format = format - end - - def format_arguments= (arguments) - @format_arguments = arguments - end - - def finish - @current = @total - @is_finished = true - show_progress - end - - def halt - @is_finished = true - show_progress - end - - def set (count) - if count < 0 || count > @total - raise "invalid count: #{count} (total: #{@total})" - end - @current = count - show_progress - @previous = @current - end - - def inc (step = 1) - @current += step - @current = @total if @current > @total - show_progress - @previous = @current - end - - def inspect - "(ProgressBar: #{@current}/#{@total})" - end - end - - class CommandPattern - class AbstractCommandError < Exception; end - class UnknownCommandError < RuntimeError; end - class CommandAlreadyExists < RuntimeError; end - - class << self - def add(command) - command = command.new if command.kind_of?(Class) - - @commands ||= {} - if @commands.has_key?(command.name) - raise CommandAlreadyExists - else - @commands[command.name] = command - end - - if command.respond_to?(:altname) - unless @commands.has_key?(command.altname) - @commands[command.altname] = command - end - end - end - - def <<(command) - add(command) - end - - attr_accessor :default - def default=(command) #:nodoc: - if command.kind_of?(CommandPattern) - @default = command - elsif command.kind_of?(Class) - @default = command.new - elsif @commands.has_key?(command) - @default = @commands[command] - else - raise UnknownCommandError - end - end - - def command?(command) - @commands.has_key?(command) - end - - def command(command) - if command?(command) - @commands[command] - else - @default - end - end - - def [](cmd) - self.command(cmd) - end - - def default_ioe(ioe = {}) - ioe[:input] ||= $stdin - ioe[:output] ||= $stdout - ioe[:error] ||= $stderr - ioe - end - end - - def [](args, opts = {}, ioe = {}) - call(args, opts, ioe) - end - - def name - raise AbstractCommandError - end - - def call(args, opts = {}, ioe = {}) - raise AbstractCommandError - end - - def help - raise AbstractCommandError - end - - end - - class CommandHelp < CommandPattern - def name - "help" - end - - def call(args, opts = {}, ioe = {}) - ioe = CommandPattern.default_ioe(ioe) - - help_on = args.shift - - if CommandPattern.command?(help_on) - ioe[:output] << CommandPattern[help_on].help - elsif help_on == "commands" - ioe[:output] << <<-EOH -The commands known to minitar are: - - minitar create Creates a new tarfile. - minitar extract Extracts files from a tarfile. - minitar list Lists files in the tarfile. - -All commands accept the options --verbose and --progress, which are -mutually exclusive. In "minitar list", --progress means the same as ---verbose. - - --verbose, -V Performs the requested command verbosely. - --progress, -P Shows a progress bar, if appropriate, for the action - being performed. - - EOH - else - ioe[:output] << "Unknown command: #{help_on}\n" unless help_on.nil? or help_on.empty? - ioe[:output] << self.help - end - - 0 - end - - def help - help = <<-EOH -This is a basic help message containing pointers to more information on -how to use this command-line tool. Try: - - minitar help commands list all 'minitar' commands - minitar help <COMMAND> show help on <COMMAND> - (e.g., 'minitar help create') - EOH - end -# minitar add Adds a file to an existing tarfile. -# minitar delete Deletes a file from an existing tarfile. - end - - class CommandCreate < CommandPattern - def name - "create" - end - - def altname - "cr" - end - - def call(args, opts = {}, ioe = {}) - argv = [] - - while (arg = args.shift) - case arg - when '--compress', '-z' - opts[:compress] = true - else - argv << arg - end - end - - if argv.size < 2 - ioe[:output] << "Not enough arguments.\n\n" - CommandPattern["help"][["create"]] - return 255 - end - - output = argv.shift - if '-' == output - opts[:name] = "STDOUT" - output = ioe[:output] - opts[:output] = ioe[:error] - else - opts[:name] = output - output = File.open(output, "wb") - opts[:output] = ioe[:output] - end - - if opts[:name] =~ /\.tar\.gz$|\.tgz$/ or opts[:compress] - output = Zlib::GzipWriter.new(output) - end - - files = [] - if argv.include?("--") - # Read stdin for the list of files. - files = "" - files << ioe[:input].read while not ioe[:input].eof? - files = files.split(/\r\n|\n|\r/) - args.delete("--") - end - - files << argv.to_a - files.flatten! - - if opts[:verbose] - watcher = lambda do |action, name, stats| - opts[:output] << "#{name}\n" if action == :dir or action == :file_done - end - finisher = lambda { opts[:output] << "\n" } - elsif opts[:progress] - progress = ProgressBar.new(opts[:name], 1) - watcher = lambda do |action, name, stats| - case action - when :file_start, :dir - progress.title = File.basename(name) - if action == :dir - progress.total += 1 - progress.inc - else - progress.total += stats[:size] - end - when :file_progress - progress.inc(stats[:currinc]) - end - end - finisher = lambda do - progress.title = opts[:name] - progress.finish - end - else - watcher = nil - finisher = lambda { } - end - - Archive::Tar::Minitar.pack(files, output, &watcher) - finisher.call - 0 - ensure - output.close if output and not output.closed? - end - - def help - help = <<-EOH - minitar create [OPTIONS] <tarfile|-> <file|directory|-->+ - -Creates a new tarfile. If the tarfile is named .tar.gz or .tgz, then it -will be compressed automatically. If the tarfile is "-", then it will be -output to standard output (stdout) so that minitar may be piped. - -The files or directories that will be packed into the tarfile are -specified after the name of the tarfile itself. Directories will be -processed recursively. If the token "--" is found in the list of files -to be packed, additional filenames will be read from standard input -(stdin). If any file is not found, the packaging will be halted. - -create Options: - --compress, -z Compresses the tarfile with gzip. - - EOH - end - end - - class CommandExtract < CommandPattern - def name - "extract" - end - - def altname - "ex" - end - - def call(args, opts = {}, ioe = {}) - argv = [] - output = nil - dest = "." - files = [] - - while (arg = args.shift) - case arg - when '--uncompress', '-z' - opts[:uncompress] = true - when '--pipe' - opts[:output] = ioe[:error] - output = ioe[:output] - when '--output', '-o' - dest = args.shift - else - argv << arg - end - end - - if argv.size < 1 - ioe[:output] << "Not enough arguments.\n\n" - CommandPattern["help"][["extract"]] - return 255 - end - - input = argv.shift - if '-' == input - opts[:name] = "STDIN" - input = ioe[:input] - else - opts[:name] = input - input = File.open(input, "rb") - end - - if opts[:name] =~ /\.tar\.gz$|\.tgz$/ or opts[:uncompress] - input = Zlib::GzipReader.new(input) - end - - files << argv.to_a - files.flatten! - - if opts[:verbose] - watcher = lambda do |action, name, stats| - opts[:output] << "#{name}\n" if action == :dir or action == :file_done - end - finisher = lambda { opts[:output] << "\n" } - elsif opts[:progress] - progress = ProgressBar.new(opts[:name], 1) - watcher = lambda do |action, name, stats| - case action - when :file_start, :dir - progress.title = File.basename(name) - if action == :dir - progress.total += 1 - progress.inc - else - progress.total += stats[:entry].size - end - when :file_progress - progress.inc(stats[:currinc]) - end - end - finisher = lambda do - progress.title = opts[:name] - progress.finish - end - else - watcher = nil - finisher = lambda { } - end - - if output.nil? - Archive::Tar::Minitar.unpack(input, dest, files, &watcher) - finisher.call - else - Archive::Tar::Minitar::Input.open(input) do |inp| - inp.each do |entry| - stats = { - :mode => entry.mode, - :mtime => entry.mtime, - :size => entry.size, - :gid => entry.gid, - :uid => entry.uid, - :current => 0, - :currinc => 0, - :entry => entry - } - - if files.empty? or files.include?(entry.full_name) - if entry.directory? - puts "Directory: #{entry.full_name}" - watcher[:dir, dest, stats] unless watcher.nil? - else - puts "File: #{entry.full_name}" - watcher[:file_start, destfile, stats] unless watcher.nil? - loop do - data = entry.read(4096) - break unless data - stats[:currinc] = output.write(data) - stats[:current] += stats[:currinc] - - watcher[:file_progress, name, stats] unless watcher.nil? - end - watcher[:file_done, name, stats] unless watcher.nil? - end - end - end - end - end - - 0 - end - - def help - help = <<-EOH - minitar extract [OPTIONS] <tarfile|-> [<file>+] - -Extracts files from an existing tarfile. If the tarfile is named .tar.gz -or .tgz, then it will be uncompressed automatically. If the tarfile is -"-", then it will be read from standard input (stdin) so that minitar -may be piped. - -The files or directories that will be extracted from the tarfile are -specified after the name of the tarfile itself. Directories will be -processed recursively. Files must be specified in full. A file -"foo/bar/baz.txt" cannot simply be specified by specifying "baz.txt". -Any file not found will simply be skipped and an error will be reported. - -extract Options: - --uncompress, -z Uncompresses the tarfile with gzip. - --pipe Emits the extracted files to STDOUT for piping. - --output, -o Extracts the files to the specified directory. - - EOH - end - end - - class CommandList < CommandPattern - def name - "list" - end - - def altname - "ls" - end - - def modestr(mode) - s = "---" - s[0] = ?r if (mode & 4) == 4 - s[1] = ?w if (mode & 2) == 2 - s[2] = ?x if (mode & 1) == 1 - s - end - - def call(args, opts = {}, ioe = {}) - argv = [] - output = nil - dest = "." - files = [] - opts[:field] = "name" - - while (arg = args.shift) - case arg - when '--sort', '-S' - opts[:sort] = true - opts[:field] = args.shift - when '--reverse', '-R' - opts[:reverse] = true - opts[:sort] = true - when '--uncompress', '-z' - opts[:uncompress] = true - when '-l' - opts[:verbose] = true - else - argv << arg - end - end - - if argv.size < 1 - ioe[:output] << "Not enough arguments.\n\n" - CommandPattern["help"][["list"]] - return 255 - end - - input = argv.shift - if '-' == input - opts[:name] = "STDIN" - input = ioe[:input] - else - opts[:name] = input - input = File.open(input, "rb") - end - - if opts[:name] =~ /\.tar\.gz$|\.tgz$/ or opts[:uncompress] - input = Zlib::GzipReader.new(input) - end - - files << argv.to_a - files.flatten! - - if opts[:verbose] or opts[:progress] - format = "%10s %4d %8s %8s %8d %12s %s" - datefmt = "%b %d %Y" - timefmt = "%b %d %H:%M" - fields = %w(permissions inodes user group size date fullname) - else - format = "%s" - fields = %w(fullname) - end - - opts[:field] = opts[:field].intern - opts[:field] = :full_name if opts[:field] == :name - - output = [] - - Archive::Tar::Minitar::Input.open(input) do |inp| - today = Time.now - oneyear = Time.mktime(today.year - 1, today.month, today.day) - inp.each do |entry| - value = format % fields.map do |ff| - case ff - when "permissions" - s = entry.directory? ? "d" : "-" - s << modestr(entry.mode / 0100) - s << modestr(entry.mode / 0010) - s << modestr(entry.mode) - when "inodes" - entry.size / 512 - when "user" - entry.uname || entry.uid || 0 - when "group" - entry.gname || entry.gid || 0 - when "size" - entry.size - when "date" - if Time.at(entry.mtime) > (oneyear) - Time.at(entry.mtime).strftime(timefmt) - else - Time.at(entry.mtime).strftime(datefmt) - end - when "fullname" - entry.full_name - end - end - - if opts[:sort] - output << [entry.send(opts[:field]), value] - else - ioe[:output] << value << "\n" - end - - end - end - - if opts[:sort] - output = output.sort { |a, b| a[0] <=> b[0] } - if opts[:reverse] - output.reverse_each { |oo| ioe[:output] << oo[1] << "\n" } - else - output.each { |oo| ioe[:output] << oo[1] << "\n" } - end - end - - 0 - end - - def help - help = <<-EOH - minitar list [OPTIONS] <tarfile|-> [<file>+] - -Lists files in an existing tarfile. If the tarfile is named .tar.gz or -.tgz, then it will be uncompressed automatically. If the tarfile is "-", -then it will be read from standard input (stdin) so that minitar may be -piped. - -If --verbose or --progress is specified, then the file list will be -similar to that produced by the Unix command "ls -l". - -list Options: - --uncompress, -z Uncompresses the tarfile with gzip. - --sort [<FIELD>], -S Sorts the list of files by the specified - field. The sort defaults to the filename. - --reverse, -R Reverses the sort. - -l Lists the files in detail. - -Sort Fields: - name, mtime, size - - EOH - end - end - - CommandPattern << CommandHelp - CommandPattern << CommandCreate - CommandPattern << CommandExtract - CommandPattern << CommandList -# CommandPattern << CommandAdd -# CommandPattern << CommandDelete - - def self.run(argv, input = $stdin, output = $stdout, error = $stderr) - ioe = { - :input => input, - :output => output, - :error => error, - } - opts = { } - - if argv.include?("--version") - output << <<-EOB -minitar #{Archive::Tar::Minitar::VERSION} - Copyright 2004 Mauricio Julio Fernández Pradier and Austin Ziegler - This is free software with ABSOLUTELY NO WARRANTY. - - see http://rubyforge.org/projects/ruwiki for more information - EOB - end - - if argv.include?("--verbose") or argv.include?("-V") - opts[:verbose] = true - argv.delete("--verbose") - argv.delete("-V") - end - - if argv.include?("--progress") or argv.include?("-P") - opts[:progress] = true - opts[:verbose] = false - argv.delete("--progress") - argv.delete("-P") - end - - command = CommandPattern[(argv.shift or "").downcase] - command ||= CommandPattern["help"] - return command[argv, opts, ioe] - end -end diff --git a/tags/version_0_5_0/minitar/tests/tc_tar.rb b/tags/version_0_5_0/minitar/tests/tc_tar.rb deleted file mode 100644 index 542eea4..0000000 --- a/tags/version_0_5_0/minitar/tests/tc_tar.rb +++ /dev/null @@ -1,624 +0,0 @@ -#!/usr/bin/env ruby -#-- -# Ruwiki version 0.8.0 -# Copyright © 2002 - 2004, Digikata and HaloStatue -# Alan Chen (alan@digikata.com) -# Austin Ziegler (ruwiki@halostatue.ca) -# -# Licensed under the same terms as Ruby. -# -# $Id$ -#++ - -$LOAD_PATH.unshift("#{File.dirname(__FILE__)}/../lib") if __FILE__ == $0 - -require 'archive/tar/minitar' -require 'test/unit' -require 'stringio' -require 'yaml' -require 'zlib' - -module TarTester -private - def assert_headers_equal(h1, h2) - fields = %w(name 100 mode 8 uid 8 gid 8 size 12 mtime 12 checksum 8 - typeflag 1 linkname 100 magic 6 version 2 uname 32 gname 32 - devmajor 8 devminor 8 prefix 155) - offset = 0 - until fields.empty? - name = fields.shift - length = fields.shift.to_i - if name == "checksum" - chksum_off = offset - offset += length - next - end - assert_equal(h1[offset, length], h2[offset, length], - "Field #{name} of the tar header differs.") - offset += length - end - assert_equal(h1[chksum_off, 8], h2[chksum_off, 8], "Checksumes differ.") - end - - def tar_file_header(fname, dname, mode, length) - h = header("0", fname, dname, length, mode) - checksum = calc_checksum(h) - header("0", fname, dname, length, mode, checksum) - end - - def tar_dir_header(name, prefix, mode) - h = header("5", name, prefix, 0, mode) - checksum = calc_checksum(h) - header("5", name, prefix, 0, mode, checksum) - end - - def header(type, fname, dname, length, mode, checksum = nil) - checksum ||= " " * 8 - arr = [ASCIIZ(fname, 100), Z(to_oct(mode, 7)), Z(to_oct(nil, 7)), - Z(to_oct(nil, 7)), Z(to_oct(length, 11)), Z(to_oct(0, 11)), - checksum, type, "\0" * 100, "ustar\0", "00", ASCIIZ("", 32), - ASCIIZ("", 32), Z(to_oct(nil, 7)), Z(to_oct(nil, 7)), - ASCIIZ(dname, 155) ] - arr = arr.join("").split(//).map{ |x| x[0] } - h = arr.pack("C100C8C8C8C12C12C8CC100C6C2C32C32C8C8C155") - ret = h + "\0" * (512 - h.size) - assert_equal(512, ret.size) - ret - end - - def calc_checksum(header) - sum = header.unpack("C*").inject { |s, a| s + a } - SP(Z(to_oct(sum, 6))) - end - - def to_oct(n, pad_size) - if n.nil? - "\0" * pad_size - else - "%0#{pad_size}o" % n - end - end - - def ASCIIZ(str, length) - str + "\0" * (length - str.length) - end - - def SP(s) - s + " " - end - - def Z(s) - s + "\0" - end - - def SP_Z(s) - s + " \0" - end -end - -class TC_Tar__Header < Test::Unit::TestCase - include Archive::Tar::Minitar - include TarTester - - def test_arguments_are_checked - e = ArgumentError - assert_raises(e) { Archive::Tar::PosixHeader.new(:name => "", :size => "", :mode => "") } - assert_raises(e) { Archive::Tar::PosixHeader.new(:name => "", :size => "", :prefix => "") } - assert_raises(e) { Archive::Tar::PosixHeader.new(:name => "", :prefix => "", :mode => "") } - assert_raises(e) { Archive::Tar::PosixHeader.new(:prefix => "", :size => "", :mode => "") } - end - - def test_basic_headers - header = { :name => "bla", :mode => 012345, :size => 10, :prefix => "", :typeflag => "0" } - assert_headers_equal(tar_file_header("bla", "", 012345, 10), - Archive::Tar::PosixHeader.new(header).to_s) - header = { :name => "bla", :mode => 012345, :size => 0, :prefix => "", :typeflag => "5" } - assert_headers_equal(tar_dir_header("bla", "", 012345), - Archive::Tar::PosixHeader.new(header).to_s) - end - - def test_long_name_works - header = { :name => "a" * 100, :mode => 012345, :size => 10, :prefix => "" } - assert_headers_equal(tar_file_header("a" * 100, "", 012345, 10), - Archive::Tar::PosixHeader.new(header).to_s) - header = { :name => "a" * 100, :mode => 012345, :size => 10, :prefix => "bb" * 60 } - assert_headers_equal(tar_file_header("a" * 100, "bb" * 60, 012345, 10), - Archive::Tar::PosixHeader.new(header).to_s) - end - - def test_new_from_stream - header = tar_file_header("a" * 100, "", 012345, 10) - h = nil - header = StringIO.new(header) - assert_nothing_raised { h = Archive::Tar::PosixHeader.new_from_stream(header) } - assert_equal("a" * 100, h.name) - assert_equal(012345, h.mode) - assert_equal(10, h.size) - assert_equal("", h.prefix) - assert_equal("ustar", h.magic) - end - - def test_new_from_stream_with_evil_name - header = tar_file_header("a \0" + "\0" * 97, "", 012345, 10) - h = nil - header = StringIO.new(header) - assert_nothing_raised{ h = Archive::Tar::PosixHeader.new_from_stream header } - assert_equal("a ", h.name) - end -end - -class TC_Tar__Writer < Test::Unit::TestCase - include Archive::Tar::Minitar - include TarTester - - class DummyIO - attr_reader :data - - def initialize - @data = "" - end - - def write(dat) - data << dat - dat.size - end - - def reset - @data = "" - end - end - - def setup - @data = "a" * 10 - @dummyos = DummyIO.new - @os = Writer.new(@dummyos) - end - - def teardown - @os.close - end - - def test_add_file_simple - @dummyos.reset - - Writer.open(@dummyos) do |os| - os.add_file_simple("lib/foo/bar", :mode => 0644, :size => 10) do |f| - f.write "a" * 10 - end - os.add_file_simple("lib/bar/baz", :mode => 0644, :size => 100) do |f| - f.write "fillme" - end - end - - assert_headers_equal(tar_file_header("lib/foo/bar", "", 0644, 10), - @dummyos.data[0, 512]) - assert_equal("a" * 10 + "\0" * 502, @dummyos.data[512, 512]) - assert_headers_equal(tar_file_header("lib/bar/baz", "", 0644, 100), - @dummyos.data[512 * 2, 512]) - assert_equal("fillme" + "\0" * 506, @dummyos.data[512 * 3, 512]) - assert_equal("\0" * 512, @dummyos.data[512 * 4, 512]) - assert_equal("\0" * 512, @dummyos.data[512 * 5, 512]) - end - - def test_write_operations_fail_after_closed - @dummyos.reset - @os.add_file_simple("sadd", :mode => 0644, :size => 20) { |f| } - @os.close - assert_raises(ClosedStream) { @os.flush } - assert_raises(ClosedStream) { @os.add_file("dfdsf", :mode => 0644) {} } - assert_raises(ClosedStream) { @os.mkdir "sdfdsf", :mode => 0644 } - end - - def test_file_name_is_split_correctly - # test insane file lengths, and: a{100}/b{155}, etc - @dummyos.reset - names = [ "#{'a' * 155}/#{'b' * 100}", "#{'a' * 151}/#{'qwer/' * 19}bla" ] - o_names = [ "#{'b' * 100}", "#{'qwer/' * 19}bla" ] - o_prefixes = [ "a" * 155, "a" * 151 ] - names.each do |name| - @os.add_file_simple(name, :mode => 0644, :size => 10) { } - end - o_names.each_with_index do |nam, i| - assert_headers_equal(tar_file_header(nam, o_prefixes[i], 0644, 10), - @dummyos.data[2 * i * 512, 512]) - end - assert_raises(FileNameTooLong) do - @os.add_file_simple(File.join("a" * 152, "b" * 10, "a" * 92), - :mode => 0644, :size => 10) { } - end - assert_raises(FileNameTooLong) do - @os.add_file_simple(File.join("a" * 162, "b" * 10), - :mode => 0644, :size => 10) { } - end - assert_raises(FileNameTooLong) do - @os.add_file_simple(File.join("a" * 10, "b" * 110), - :mode => 0644, :size => 10) { } - end - end - - def test_add_file - dummyos = StringIO.new - class << dummyos - def method_missing(meth, *a) - self.string.send(meth, *a) - end - end - os = Writer.new dummyos - content1 = ('a'..'z').to_a.join("") # 26 - content2 = ('aa'..'zz').to_a.join("") # 1352 - Writer.open(dummyos) do |os| - os.add_file("lib/foo/bar", :mode => 0644) { |f, opts| f.write "a" * 10 } - os.add_file("lib/bar/baz", :mode => 0644) { |f, opts| f.write content1 } - os.add_file("lib/bar/baz", :mode => 0644) { |f, opts| f.write content2 } - os.add_file("lib/bar/baz", :mode => 0644) { |f, opts| } - end - assert_headers_equal(tar_file_header("lib/foo/bar", "", 0644, 10), - dummyos[0, 512]) - assert_equal(%Q(#{"a" * 10}#{"\0" * 502}), dummyos[512, 512]) - offset = 512 * 2 - [content1, content2, ""].each do |data| - assert_headers_equal(tar_file_header("lib/bar/baz", "", 0644, - data.size), dummyos[offset, 512]) - offset += 512 - until !data || data == "" - chunk = data[0, 512] - data[0, 512] = "" - assert_equal(chunk + "\0" * (512 - chunk.size), - dummyos[offset, 512]) - offset += 512 - end - end - assert_equal("\0" * 1024, dummyos[offset, 1024]) - end - - def test_add_file_tests_seekability - assert_raises(Archive::Tar::Minitar::NonSeekableStream) do - @os.add_file("libdfdsfd", :mode => 0644) { |f| } - end - end - - def test_write_header - @dummyos.reset - @os.add_file_simple("lib/foo/bar", :mode => 0644, :size => 0) { |f| } - @os.flush - assert_headers_equal(tar_file_header("lib/foo/bar", "", 0644, 0), - @dummyos.data[0, 512]) - @dummyos.reset - @os.mkdir("lib/foo", :mode => 0644) - assert_headers_equal(tar_dir_header("lib/foo", "", 0644), - @dummyos.data[0, 512]) - @os.mkdir("lib/bar", :mode => 0644) - assert_headers_equal(tar_dir_header("lib/bar", "", 0644), - @dummyos.data[512 * 1, 512]) - end - - def test_write_data - @dummyos.reset - @os.add_file_simple("lib/foo/bar", :mode => 0644, :size => 10) do |f| - f.write @data - end - @os.flush - assert_equal(@data + ("\0" * (512-@data.size)), - @dummyos.data[512, 512]) - end - - def test_file_size_is_checked - @dummyos.reset - assert_raises(Archive::Tar::Minitar::Writer::BoundedStream::FileOverflow) do - @os.add_file_simple("lib/foo/bar", :mode => 0644, :size => 10) do |f| - f.write "1" * 100 - end - end - assert_nothing_raised do - @os.add_file_simple("lib/foo/bar", :mode => 0644, :size => 10) {|f| } - end - end -end - -class TC_Tar__Reader < Test::Unit::TestCase - include Archive::Tar::Minitar - include TarTester - - def setup - end - - def teardown - end - - def test_multiple_entries - str = tar_file_header("lib/foo", "", 010644, 10) + "\0" * 512 - str += tar_file_header("bar", "baz", 0644, 0) - str += tar_dir_header("foo", "bar", 012345) - str += "\0" * 1024 - names = %w[lib/foo bar foo] - prefixes = ["", "baz", "bar"] - modes = [010644, 0644, 012345] - sizes = [10, 0, 0] - isdir = [false, false, true] - isfile = [true, true, false] - Reader.new(StringIO.new(str)) do |is| - i = 0 - is.each_entry do |entry| - assert_kind_of(Reader::EntryStream, entry) - assert_equal(names[i], entry.name) - assert_equal(prefixes[i], entry.prefix) - assert_equal(sizes[i], entry.size) - assert_equal(modes[i], entry.mode) - assert_equal(isdir[i], entry.directory?) - assert_equal(isfile[i], entry.file?) - if prefixes[i] != "" - assert_equal(File.join(prefixes[i], names[i]), entry.full_name) - else - assert_equal(names[i], entry.name) - end - i += 1 - end - assert_equal(names.size, i) - end - end - - def test_rewind_entry_works - content = ('a'..'z').to_a.join(" ") - str = tar_file_header("lib/foo", "", 010644, content.size) + content + - "\0" * (512 - content.size) - str << "\0" * 1024 - Reader.new(StringIO.new(str)) do |is| - is.each_entry do |entry| - 3.times do - entry.rewind - assert_equal(content, entry.read) - assert_equal(content.size, entry.pos) - end - end - end - end - - def test_rewind_works - content = ('a'..'z').to_a.join(" ") - str = tar_file_header("lib/foo", "", 010644, content.size) + content + - "\0" * (512 - content.size) - str << "\0" * 1024 - Reader.new(StringIO.new(str)) do |is| - 3.times do - is.rewind - i = 0 - is.each_entry do |entry| - assert_equal(content, entry.read) - i += 1 - end - assert_equal(1, i) - end - end - end - - def test_read_works - contents = ('a'..'z').inject(""){|s, x| s << x * 100} - str = tar_file_header("lib/foo", "", 010644, contents.size) + contents - str += "\0" * (512 - (str.size % 512)) - Reader.new(StringIO.new(str)) do |is| - is.each_entry do |entry| - assert_kind_of(Reader::EntryStream, entry) - data = entry.read(3000) # bigger than contents.size - assert_equal(contents, data) - assert_equal(true, entry.eof?) - end - end - Reader.new(StringIO.new(str)) do |is| - is.each_entry do |entry| - assert_kind_of(Reader::EntryStream, entry) - data = entry.read(100) - (entry.size - data.size).times {|i| data << entry.getc.chr } - assert_equal(contents, data) - assert_equal(nil, entry.read(10)) - assert_equal(true, entry.eof?) - end - end - Reader.new(StringIO.new(str)) do |is| - is.each_entry do |entry| - assert_kind_of(Reader::EntryStream, entry) - data = entry.read - assert_equal(contents, data) - assert_equal(nil, entry.read(10)) - assert_equal(nil, entry.read) - assert_equal(nil, entry.getc) - assert_equal(true, entry.eof?) - end - end - end - - def test_eof_works - str = tar_file_header("bar", "baz", 0644, 0) - Reader.new(StringIO.new(str)) do |is| - is.each_entry do |entry| - assert_kind_of(Reader::EntryStream, entry) - data = entry.read - assert_equal(nil, data) - assert_equal(nil, entry.read(10)) - assert_equal(nil, entry.read) - assert_equal(nil, entry.getc) - assert_equal(true, entry.eof?) - end - end - str = tar_dir_header("foo", "bar", 012345) - Reader.new(StringIO.new(str)) do |is| - is.each_entry do |entry| - assert_kind_of(Reader::EntryStream, entry) - data = entry.read - assert_equal(nil, data) - assert_equal(nil, entry.read(10)) - assert_equal(nil, entry.read) - assert_equal(nil, entry.getc) - assert_equal(true, entry.eof?) - end - end - str = tar_dir_header("foo", "bar", 012345) - str += tar_file_header("bar", "baz", 0644, 0) - str += tar_file_header("bar", "baz", 0644, 0) - Reader.new(StringIO.new(str)) do |is| - is.each_entry do |entry| - assert_kind_of(Reader::EntryStream, entry) - data = entry.read - assert_equal(nil, data) - assert_equal(nil, entry.read(10)) - assert_equal(nil, entry.read) - assert_equal(nil, entry.getc) - assert_equal(true, entry.eof?) - end - end - end -end - -class TC_Tar__Input < Test::Unit::TestCase - include Archive::Tar::Minitar - include TarTester - - require 'rbconfig' - - TEST_TGZ = "\037\213\010\000\001B1A\000\vKI,I\324+I,\322K\257b\240\0250\000\002sSS\254\342 `dj\306``nnnbndbjd\000\0247336`P0\240\231\213\220@i1\320\367@+\351a\327 \004\362\335\034\f\313\034\r\035\031\270\337Ns\344b2\344q\335\375M\304\266QM1W\357\321>\221U\021\005\246\306\367\356\367u3\262;\212\004\265\236\\\334}\351,\377\037;\217\223\301e\247\030\024\\\236\211\277\347\346sii\265\010\330\355\234\240\362\274\371[\202\361\366\302S\316\335o&~m\237r\355\377\303\230\365\352WNW\334\266_\373\273\237\347Q\315t?\263{\377?\006\271\337?\367\207\325\346]\371\376y\307_\234~d\3772\265\346\261}\323\317\373\315\352\377O\376\271/\305\377?X\253\324\303S\373\361\347\277\372^)\267\377\363\03460\331\311\\wW|\031\203\300@\207\325p\004i\2319\251\3064\266\203P\376702B\313\377\246\246\006&\243\371\237\036 $#\263X\001\210@\351@\301XO\201\227k\240]4\nF\301(\030\005\243\200\036\000\000\004\330t\023\000\f\000\000" - FILETIMES = Time.mktime(2004).to_i - - TEST_CONTENTS = [ - [ "data.tar.gz", 174, 0755 ], - [ "file3", 18, 0755 ], - ] - - TEST_DATA_CONTENTS = [ - [ "data", 0, 010644 ], - [ "data/file1", 16, 010644 ], - [ "data/file2", 16, 010644 ], - [ "data/__dir__", 0, 010644 ], - ] - - def setup - FileUtils.mkdir_p("data__") - end - - def teardown - FileUtils.rm_rf("data__") - end - - def test_each_works - gzr = Zlib::GzipReader.new(StringIO.new(TEST_TGZ)) - Input.open(gzr) do |is| - ii = 0 - is.each_with_index do |entry, ii| - assert_kind_of(Reader::EntryStream, entry) - assert_equal(TEST_CONTENTS[ii][0], entry.name) - assert_equal(TEST_CONTENTS[ii][1], entry.size) - assert_equal(TEST_CONTENTS[ii][2], entry.mode) - assert_equal(FILETIMES, entry.mtime) - - if 0 == ii - gzr2 = Zlib::GzipReader.new(StringIO.new(entry.read)) - Input.open(gzr2) do |is2| - jj = 0 - is2.each_with_index do |entry2, jj| - assert_kind_of(Reader::EntryStream, entry2) - assert_equal(TEST_DATA_CONTENTS[jj][0], entry2.name) - assert_equal(TEST_DATA_CONTENTS[jj][1], entry2.size) - assert_equal(TEST_DATA_CONTENTS[jj][2], entry2.mode) - assert_equal(FILETIMES, entry2.mtime) - end - assert_equal(3, jj) - end - end - end - assert_equal(1, ii) - end - end - - def test_extract_entry_works - gzr = Zlib::GzipReader.new(StringIO.new(TEST_TGZ)) - Input.open(gzr) do |is| - ii = 0 - is.each_with_index do |entry, ii| - is.extract_entry("data__", entry) - name = File.join("data__", entry.name) - - if entry.directory? - assert(File.directory?(name)) - else - assert(File.file?(name)) - - assert_equal(TEST_CONTENTS[ii][1], File.stat(name).size) - end - assert_equal(TEST_CONTENTS[ii][2], File.stat(name).mode) unless RUBY_PLATFORM =~ /win32/ - - if 0 == ii - begin - ff = File.open(name, "rb") - gzr2 = Zlib::GzipReader.new(ff) - Input.open(gzr2) do |is2| - jj = 0 - is2.each_with_index do |entry2, jj| - is2.extract_entry("data__", entry2) - name2 = File.join("data__", entry2.name) - - if entry2.directory? - assert(File.directory?(name2)) - else - assert(File.file?(name2)) - assert_equal(TEST_DATA_CONTENTS[jj][1], File.stat(name2).size, name2) - end - assert_equal(TEST_DATA_CONTENTS[jj][2], File.stat(name2).mode, name2) unless RUBY_PLATFORM =~ /win32/ - end - end - ensure - ff.close unless ff.closed? - end - end - end - assert_equal(1, ii) - end - end -end - -class TC_Tar__Output < Test::Unit::TestCase - include Archive::Tar::Minitar - include TarTester - - def setup - FileUtils.mkdir_p("data__") - %w(a b c).each do |filename| - name = File.join("data__", filename) - File.open(name, "wb") { |f| f.puts "#{name}: 123456789012345678901234567890" } - end - @tarfile = "data__/bla2.tar" - end - - def teardown - FileUtils.rm_rf("data__") - end - - def test_file_looks_good - Output.open(@tarfile) do |os| - Dir.chdir("data__") do - %w(a b c).each do |name| - stat = File.stat(name) - opts = { :size => stat.size, :mode => 0644 } - os.tar.add_file_simple(name, opts) do |ss| - File.open(name, "rb") { |ff| ss.write(ff.read(4096)) until ff.eof? } - end - end - end - end - ff = File.open(@tarfile, "rb") - Reader.open(ff) do |is| - ii = 0 - is.each do |entry| - case ii - when 0 - assert_equal("a", entry.name) - when 1 - assert_equal("b", entry.name) - when 2 - assert_equal("c", entry.name) - end - ii += 1 - end - assert_equal(3, ii) - end - ensure - ff.close if ff - end -end diff --git a/tags/version_0_5_0/minitar/tests/testall.rb b/tags/version_0_5_0/minitar/tests/testall.rb deleted file mode 100644 index 9c65d0f..0000000 --- a/tags/version_0_5_0/minitar/tests/testall.rb +++ /dev/null @@ -1,20 +0,0 @@ -#!/usr/bin/env ruby -#-- -# Ruwiki version 0.8.0 -# Copyright © 2002 - 2003, Digikata and HaloStatue -# Alan Chen (alan@digikata.com) -# Austin Ziegler (ruwiki@halostatue.ca) -# -# Licensed under the same terms as Ruby. -# -# $Id$ -#++ - -$LOAD_PATH.unshift("#{File.dirname(__FILE__)}/../lib") if __FILE__ == $0 - -puts "Checking for test cases:" -Dir['tc*.rb'].each do |testcase| - puts "\t#{testcase}" - require testcase -end -puts " " diff --git a/tags/version_0_5_1/minitar/ChangeLog b/tags/version_0_5_1/minitar/ChangeLog deleted file mode 100644 index df66842..0000000 --- a/tags/version_0_5_1/minitar/ChangeLog +++ /dev/null @@ -1,11 +0,0 @@ -Revision history for Ruby library Archive::Tar::Minitar. Unless explicitly -noted otherwise, all changes are produced by Austin Ziegler -<minitar@halostatue.ca>. - -== 0.5.1 -* Fixed a variable name error. - -== Archive::Tar::Minitar 0.5.0 -* Initial release. Does files and directories. Command does create, extract, -* and list. - diff --git a/tags/version_0_5_1/minitar/Install b/tags/version_0_5_1/minitar/Install deleted file mode 100644 index 1f75cee..0000000 --- a/tags/version_0_5_1/minitar/Install +++ /dev/null @@ -1,6 +0,0 @@ -Installing this package is as simple as: - -% ruby install.rb - -Alternatively, you can use the RubyGem version of Archive::Tar::Minitar -available as archive-tar-minitar-0.5.1.gem from the usual sources. diff --git a/tags/version_0_5_1/minitar/README b/tags/version_0_5_1/minitar/README deleted file mode 100644 index 9c25a34..0000000 --- a/tags/version_0_5_1/minitar/README +++ /dev/null @@ -1,66 +0,0 @@ -Archive::Tar::Minitar README -============================ -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 release is version 0.5.1, offering a bugfix over version 0.5.0. 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. - -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. -# -# $Id$ diff --git a/tags/version_0_5_1/minitar/Rakefile b/tags/version_0_5_1/minitar/Rakefile deleted file mode 100644 index 449f8c0..0000000 --- a/tags/version_0_5_1/minitar/Rakefile +++ /dev/null @@ -1,112 +0,0 @@ -#! /usr/bin/env rake -$LOAD_PATH.unshift('lib') - -require 'rubygems' -require 'rake/testtask' -require 'rake/gempackagetask' -require 'rake/contrib/rubyforgepublisher' -require 'archive/tar/minitar' -require 'zlib' - -DISTDIR = "archive-tar-minitar-#{Archive::Tar::Minitar::VERSION}" -TARDIST = "../#{DISTDIR}.tar.gz" - -DATE_RE = %r<(\d{4})[./-]?(\d{2})[./-]?(\d{2})(?:[\sT]?(\d{2})[:.]?(\d{2})[:.]?(\d{2})?)?> - -if ENV['RELEASE_DATE'] - year, month, day, hour, minute, second = DATE_RE.match(ENV['RELEASE_DATE']).captures - year ||= 0 - month ||= 0 - day ||= 0 - hour ||= 0 - minute ||= 0 - second ||= 0 - ReleaseDate = Time.mktime(year, month, day, hour, minute, second) -else - ReleaseDate = nil -end - - # This rakefile must do the following: - # 1. Run the unit tests, successfully. - # 2. Modify the Readme.tarfile, Readme.rubygems, and data files to include - # the proper version #. - # 2. Create a package. - # 3. Modify the existing pages so that properties!editable is set to - # +false+. - # 4. - -task :test do |t| - require 'test/unit/testsuite' - require 'test/unit/ui/console/testrunner' - - runner = Test::Unit::UI::Console::TestRunner - - $LOAD_PATH.unshift('tests') - $stderr.puts "Checking for test cases:" if t.verbose - Dir['tests/tc_*.rb'].each do |testcase| - $stderr.puts "\t#{testcase}" if t.verbose - load testcase - end - - suite = Test::Unit::TestSuite.new - - ObjectSpace.each_object(Class) do |testcase| - suite << testcase.suite if testcase < Test::Unit::TestCase - end - - runner.run(suite) -end - -spec = eval(File.read("archive-tar-minitar.gemspec")) -desc "Build the RubyGem for Archive::Tar::Minitar." -Rake::GemPackageTask.new(spec) do |g| - g.need_tar = false - g.need_zip = false - g.package_dir = ".." -end - -desc "Build an Archive::Tar::Minitar .tar.gz distribution." -task :tar => [ TARDIST ] -file TARDIST do |t| - current = File.basename(Dir.pwd) - Dir.chdir("..") do - begin - files = Dir["#{current}/**/*"].select { |dd| dd !~ %r{(?:/CVS/?|~$)} } - files.map! do |dd| - ddnew = dd.gsub(/^#{current}/, DISTDIR) - mtime = ReleaseDate || File.stat(dd).mtime - if File.directory?(dd) - { :name => ddnew, :mode => 0555, :dir => true, :mtime => mtime } - else - if dd =~ %r{bin/} - mode = 0755 - else - mode = 0644 - end - data = File.read(dd) - { :name => ddnew, :mode => mode, :data => data, :size => data.size, - :mtime => mtime } - end - end - - ff = File.open(t.name.gsub(%r{^\.\./}o, ''), "wb") - gz = Zlib::GzipWriter.new(ff) - tw = Archive::Tar::Minitar::Writer.new(gz) - - files.each do |entry| - if entry[:dir] - tw.mkdir(entry[:name], entry) - else - tw.add_file_simple(entry[:name], entry) { |os| os.write(entry[:data]) } - end - end - ensure - tw.close if tw - gz.close if gz - end - end -end - -desc "Build everything." -task :default => [ :test, :tar, :gem ] do -end diff --git a/tags/version_0_5_1/minitar/bin/minitar b/tags/version_0_5_1/minitar/bin/minitar deleted file mode 100644 index cfdf85e..0000000 --- a/tags/version_0_5_1/minitar/bin/minitar +++ /dev/null @@ -1,26 +0,0 @@ -#!/usr/bin/env ruby -#-- -# Archive::Tar::Minitar 0.5.1 -# 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. -# -# It is licensed under the GNU General Public Licence or Ruby's licence. -# -# $Id$ -#++ - - # 1) Try to load Archive::Tar::Minitar from the gem. - # 2) Try to load Archive::Tar::Minitar from $LOAD_PATH. -begin - require 'rubygems' - require_gem 'archive-tar-minitar', '= 0.5.1' -rescue LoadError - require 'archive/tar/minitar' -end - -require 'archive/tar/minitar/command' - -exit Archive::Tar::Minitar::Command.run(ARGV) diff --git a/tags/version_0_5_1/minitar/install.rb b/tags/version_0_5_1/minitar/install.rb deleted file mode 100644 index 4bd3d7a..0000000 --- a/tags/version_0_5_1/minitar/install.rb +++ /dev/null @@ -1,262 +0,0 @@ -#! /usr/bin/env ruby -#-- -# Copyright 2004 Austin Ziegler <ruby-install@halostatue.ca> -# Install utility. Based on the original installation script for rdoc by the -# Pragmatic Programmers. -# -# This program is free software. It may be redistributed and/or modified under -# the terms of the GPL version 2 (or later) or the Ruby licence. -# -# Usage -# ----- -# In most cases, if you have a typical project layout, you will need to do -# absolutely nothing to make this work for you. This layout is: -# -# bin/ # executable files -- "commands" -# lib/ # the source of the library -# tests/ # unit tests -# -# The default behaviour: -# 1) Run all unit test files (ending in .rb) found in all directories under -# tests/. -# 2) Build Rdoc documentation from all files in bin/ (excluding .bat and .cmd), -# all .rb files in lib/, ./README, ./ChangeLog, and ./Install. -# 3) Build ri documentation from all files in bin/ (excluding .bat and .cmd), -# and all .rb files in lib/. This is disabled by default on Win32. -# 4) Install commands from bin/ into the Ruby bin directory. On Windows, if a -# if a corresponding batch file (.bat or .cmd) exists in the bin directory, -# it will be copied over as well. Otherwise, a batch file (always .bat) will -# be created to run the specified command. -# 5) Install all library files ending in .rb from lib/ into Ruby's -# site_lib/version directory. -# -# $Id$ -#++ - -require 'rbconfig' -require 'find' -require 'fileutils' -require 'rdoc/rdoc' -require 'optparse' -require 'ostruct' - -InstallOptions = OpenStruct.new - -def glob(list) - g = list.map { |i| Dir.glob(i) } - g.flatten! - g.compact! - g.reject! { |e| e =~ /CVS/ } - g -end - - # Set these values to what you want installed. -bins = glob(%w{bin/**/*}).reject { |e| e =~ /\.(bat|cmd)$/ } -rdoc = glob(%w{bin/**/* lib/**/*.rb README ChangeLog Install}).reject { |e| e=~ /\.(bat|cmd)$/ } -ri = glob(%w(bin/**/*.rb lib/**/*.rb)).reject { |e| e=~ /\.(bat|cmd)$/ } -libs = glob(%w{lib/**/*.rb}) -tests = glob(%w{tests/**/*.rb}) - -def do_bins(bins, target, strip = 'bin/') - bins.each do |bf| - obf = bf.gsub(/#{strip}/, '') - install_binfile(bf, obf, target) - end -end - -def do_libs(libs, strip = 'lib/') - libs.each do |lf| - olf = File.join(InstallOptions.site_dir, lf.gsub(/#{strip}/, '')) - op = File.dirname(olf) - File.makedirs(op, true) - File.chmod(0755, op) - File.install(lf, olf, 0755, true) - end -end - -## -# Prepare the file installation. -# -def prepare_installation - InstallOptions.rdoc = true - if RUBY_PLATFORM == "i386-mswin32" - InstallOptions.ri = false - else - InstallOptions.ri = true - end - InstallOptions.tests = true - - ARGV.options do |opts| - opts.banner = "Usage: #{File.basename($0)} [options]" - opts.separator "" - opts.on('--[no-]rdoc', 'Prevents the creation of RDoc output.', 'Default on.') do |onrdoc| - InstallOptions.rdoc = onrdoc - end - opts.on('--[no-]ri', 'Prevents the creation of RI output.', 'Default off on mswin32.') do |onri| - InstallOptions.ri = onri - end - opts.on('--[no-]tests', 'Prevents the execution of unit tests.', 'Default on.') do |ontest| - InstallOptions.tests = ontest - end - opts.on('--quick', 'Performs a quick installation. Only the', 'installation is done.') do |quick| - InstallOptions.rdoc = false - InstallOptions.ri = false - InstallOptions.tests = false - end - opts.on('--full', 'Performs a full installation. All', 'optional installation steps are run.') do |full| - InstallOptions.rdoc = true - InstallOptions.ri = true - InstallOptions.tests = true - end - opts.separator("") - opts.on_tail('--help', "Shows this help text.") do - $stderr.puts opts - exit - end - - opts.parse! - end - - bds = [".", ENV['TMP'], ENV['TEMP']] - - version = [Config::CONFIG["MAJOR"], Config::CONFIG["MINOR"]].join(".") - ld = File.join(Config::CONFIG["libdir"], "ruby", version) - - sd = Config::CONFIG["sitelibdir"] - if sd.nil? - sd = $:.find { |x| x =~ /site_ruby/ } - if sd.nil? - sd = File.join(ld, "site_ruby") - elsif sd !~ Regexp.quote(version) - sd = File.join(sd, version) - end - end - - if (destdir = ENV['DESTDIR']) - bd = "#{destdir}#{Config::CONFIG['bindir']}" - sd = "#{destdir}#{sd}" - bds << bd - - FileUtils.makedirs(bd) - FileUtils.makedirs(sd) - else - bds << Config::CONFIG['bindir'] - end - - InstallOptions.bin_dirs = bds.compact - InstallOptions.site_dir = sd - InstallOptions.bin_dir = bd - InstallOptions.lib_dir = ld -end - -## -# Build the rdoc documentation. Also, try to build the RI documentation. -# -def build_rdoc(files) - r = RDoc::RDoc.new - r.document(["--main", "README", "--title", "Diff::LCS -- A Diff Algorithm", - "--line-numbers"] + files) - -rescue RDoc::RDocError => e - $stderr.puts e.message -rescue Exception => e - $stderr.puts "Couldn't build RDoc documentation\n#{e.message}" -end - -def build_ri(files) - ri = RDoc::RDoc.new - ri.document(["--ri-site", "--merge"] + files) -rescue RDoc::RDocError => e - $stderr.puts e.message -rescue Exception => e - $stderr.puts "Couldn't build Ri documentation\n#{e.message}" -end - -def run_tests(test_list) - require 'test/unit/ui/console/testrunner' - $:.unshift "lib" - test_list.each do |test| - next if File.directory?(test) - require test - end - - tests = Test::Unit::TestSuite.new - ObjectSpace.each_object(Class) { |o| tests << o.suite if o < Test::Unit::TestCase } - - Test::Unit::UI::Console::TestRunner.run(tests) - $:.shift -end - -## -# Install file(s) from ./bin to Config::CONFIG['bindir']. Patch it on the way -# to insert a #! line; on a Unix install, the command is named as expected -# (e.g., bin/rdoc becomes rdoc); the shebang line handles running it. Under -# windows, we add an '.rb' extension and let file associations do their stuff. -def install_binfile(from, op_file, target) - tmp_dir = nil - InstallOptions.bin_dirs.each do |t| - if File.directory?(t) and File.writable?(t) - tmp_dir = t - break - end - end - - fail "Cannot find a temporary directory" unless tmp_dir - tmp_file = File.join(tmp_dir, '_tmp') - ruby = File.join(Config::CONFIG['bindir'], Config::CONFIG['ruby_install_name']) - - File.open(from) do |ip| - File.open(tmp_file, "w") do |op| - ruby = File.join(Config::CONFIG['bindir'], Config::CONFIG['ruby_install_name']) - op.puts "#!#{ruby}" - op.write ip.read - end - end - - if Config::CONFIG["target_os"] =~ /win/io - installed_wrapper = false - - if File.exists?("#{from}.bat") - FileUtils.install("#{from}.bat", File.join(target, "#{op_file}.bat"), :mode => 0755, :verbose => true) - installed_wrapper = true - end - - if File.exists?("#{from}.cmd") - FileUtils.install("#{from}.cmd", File.join(target, "#{op_file}.cmd"), :mode => 0755, :verbose => true) - installed_wrapper = true - end - - if not installed_wrapper - tmp_file2 = File.join(tmp_dir, '_tmp_wrapper') - cwn = File.join(Config::CONFIG['bindir'], op_file) - cwv = CMD_WRAPPER.gsub('<ruby>', ruby.gsub(%r{/}) { "\\" }).gsub!('<command>', cwn.gsub(%r{/}) { "\\" } ) - - File.open(tmp_file2, "wb") { |cw| cw.puts cwv } - FileUtils.install(tmp_file2, File.join(target, "#{op_file}.bat"), :mode => 0755, :verbose => true) - - File.unlink(tmp_file2) - installed_wrapper = true - end - end - FileUtils.install(tmp_file, File.join(target, op_file), :mode => 0755, :verbose => true) - File.unlink(tmp_file) -end - -CMD_WRAPPER = <<-EOS -@echo off -if "%OS%"=="Windows_NT" goto WinNT -<ruby> -x "<command>" %1 %2 %3 %4 %5 %6 %7 %8 %9 -goto done -:WinNT -<ruby> -x "<command>" %* -goto done -:done -EOS - -prepare_installation - -run_tests(tests) if InstallOptions.tests -build_rdoc(rdoc) if InstallOptions.rdoc -build_ri(ri) if InstallOptions.ri -do_bins(bins, Config::CONFIG['bindir']) -do_libs(libs) diff --git a/tags/version_0_5_1/minitar/lib/archive/tar/minitar.rb b/tags/version_0_5_1/minitar/lib/archive/tar/minitar.rb deleted file mode 100644 index 7d381e7..0000000 --- a/tags/version_0_5_1/minitar/lib/archive/tar/minitar.rb +++ /dev/null @@ -1,979 +0,0 @@ -#!/usr/bin/env ruby -#-- -# Archive::Tar::Minitar 0.5.1 -# 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. -# -# It is licensed under the GNU General Public Licence or Ruby's licence. -# -# $Id$ -#++ - -module Archive; end -module Archive::Tar; end - - # = Archive::Tar::PosixHeader - # Implements the POSIX tar header as a Ruby class. The structure of - # the POSIX tar header is: - # - # struct tarfile_entry_posix - # { // pack/unpack - # char name[100]; // ASCII (+ Z unless filled) a100/Z100 - # char mode[8]; // 0 padded, octal, null a8 /A8 - # char uid[8]; // ditto a8 /A8 - # char gid[8]; // ditto a8 /A8 - # char size[12]; // 0 padded, octal, null a12 /A12 - # char mtime[12]; // 0 padded, octal, null a12 /A12 - # char checksum[8]; // 0 padded, octal, null, space a8 /A8 - # char typeflag[1]; // see below a /a - # char linkname[100]; // ASCII + (Z unless filled) a100/Z100 - # char magic[6]; // "ustar\0" a6 /A6 - # char version[2]; // "00" a2 /A2 - # char uname[32]; // ASCIIZ a32 /Z32 - # char gname[32]; // ASCIIZ a32 /Z32 - # char devmajor[8]; // 0 padded, octal, null a8 /A8 - # char devminor[8]; // 0 padded, octal, null a8 /A8 - # char prefix[155]; // ASCII (+ Z unless filled) a155/Z155 - # }; - # - # The +typeflag+ may be one of the following known values: - # - # <tt>"0"</tt>:: Regular file. NULL should be treated as a synonym, for - # compatibility purposes. - # <tt>"1"</tt>:: Hard link. - # <tt>"2"</tt>:: Symbolic link. - # <tt>"3"</tt>:: Character device node. - # <tt>"4"</tt>:: Block device node. - # <tt>"5"</tt>:: Directory. - # <tt>"6"</tt>:: FIFO node. - # <tt>"7"</tt>:: Reserved. - # - # POSIX indicates that "A POSIX-compliant implementation must treat any - # unrecognized typeflag value as a regular file." -class Archive::Tar::PosixHeader - FIELDS = %w(name mode uid gid size mtime checksum typeflag linkname) + - %w(magic version uname gname devmajor devminor prefix) - - FIELDS.each { |field| attr_reader field.intern } - - HEADER_PACK_FORMAT = "a100a8a8a8a12a12a7aaa100a6a2a32a32a8a8a155" - HEADER_UNPACK_FORMAT = "Z100A8A8A8A12A12A8aZ100A6A2Z32Z32A8A8Z155" - - # Creates a new PosixHeader from a data stream. - def self.new_from_stream(stream) - data = stream.read(512) - fields = data.unpack(HEADER_UNPACK_FORMAT) - name = fields.shift - mode = fields.shift.oct - uid = fields.shift.oct - gid = fields.shift.oct - size = fields.shift.oct - mtime = fields.shift.oct - checksum = fields.shift.oct - typeflag = fields.shift - linkname = fields.shift - magic = fields.shift - version = fields.shift.oct - uname = fields.shift - gname = fields.shift - devmajor = fields.shift.oct - devminor = fields.shift.oct - prefix = fields.shift - - empty = (data == "\0" * 512) - - new(:name => name, :mode => mode, :uid => uid, :gid => gid, - :size => size, :mtime => mtime, :checksum => checksum, - :typeflag => typeflag, :magic => magic, :version => version, - :uname => uname, :gname => gname, :devmajor => devmajor, - :devminor => devminor, :prefix => prefix, :empty => empty) - end - - # Creates a new PosixHeader. A PosixHeader cannot be created unless the - # #name, #size, #prefix, and #mode are provided. - def initialize(vals) - unless vals[:name] && vals[:size] && vals[:prefix] && vals[:mode] - raise ArgumentError - end - - vals[:mtime] ||= 0 - vals[:checksum] ||= "" - vals[:typeflag] ||= "0" - vals[:magic] ||= "ustar" - vals[:version] ||= "00" - - FIELDS.each do |field| - instance_variable_set("@#{field}", vals[field.intern]) - end - @empty = vals[:empty] - end - - def empty? - @empty - end - - def to_s - update_checksum - header(@checksum) - end - - # Update the checksum field. - def update_checksum - hh = header(" " * 8) - @checksum = oct(calculate_checksum(hh), 6) - end - - private - def oct(num, len) - if num.nil? - "\0" * (len + 1) - else - "%0#{len}o" % num - end - end - - def calculate_checksum(hdr) - hdr.unpack("C*").inject { |aa, bb| aa + bb } - end - - def header(chksum) - arr = [name, oct(mode, 7), oct(uid, 7), oct(gid, 7), oct(size, 11), - oct(mtime, 11), chksum, " ", typeflag, linkname, magic, version, - uname, gname, oct(devmajor, 7), oct(devminor, 7), prefix] - str = arr.pack(HEADER_PACK_FORMAT) - str + "\0" * ((512 - str.size) % 512) - end -end - -require 'fileutils' -require 'find' - - # = 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. -module Archive::Tar::Minitar - VERSION = "0.5.1" - - # The exception raised when a wrapped data stream class is expected to - # respond to #rewind or #pos but does not. - class NonSeekableStream < StandardError; end - # The exception raised when a block is required for proper operation of - # the method. - class BlockRequired < ArgumentError; end - # The exception raised when operations are performed on a stream that has - # previously been closed. - class ClosedStream < StandardError; end - # The exception raised when a filename exceeds 256 bytes in length, - # the maximum supported by the standard Tar format. - class FileNameTooLong < StandardError; end - # The exception raised when a data stream ends before the amount of data - # expected in the archive's PosixHeader. - class UnexpectedEOF < StandardError; end - - # The class that writes a tar format archive to a data stream. - class Writer - # A stream wrapper that can only be written to. Any attempt to read - # from this restricted stream will result in a NameError being thrown. - class RestrictedStream - def initialize(anIO) - @io = anIO - end - - def write(data) - @io.write(data) - end - end - - # A RestrictedStream that also has a size limit. - class BoundedStream < Archive::Tar::Minitar::Writer::RestrictedStream - # The exception raised when the user attempts to write more data to - # a BoundedStream than has been allocated. - class FileOverflow < RuntimeError; end - - # The maximum number of bytes that may be written to this data - # stream. - attr_reader :limit - # The current total number of bytes written to this data stream. - attr_reader :written - - def initialize(io, limit) - @io = io - @limit = limit - @written = 0 - end - - def write(data) - raise FileOverflow if (data.size + @written) > @limit - @io.write(data) - @written += data.size - data.size - end - end - - # With no associated block, +Writer::open+ is a synonym for - # +Writer::new+. If the optional code block is given, it will be - # passed the new _writer_ as an argument and the Writer object will - # automatically be closed when the block terminates. In this instance, - # +Writer::open+ returns the value of the block. - def self.open(anIO) - writer = Writer.new(anIO) - - return writer unless block_given? - - begin - res = yield writer - ensure - writer.close - end - - res - end - - # Creates and returns a new Writer object. - def initialize(anIO) - @io = anIO - @closed = false - end - - # Adds a file to the archive as +name+. +opts+ must contain the - # following values: - # - # <tt>:mode</tt>:: The Unix file permissions mode value. - # <tt>:size</tt>:: The size, in bytes. - # - # +opts+ may contain the following values: - # - # <tt>:uid</tt>: The Unix file owner user ID number. - # <tt>:gid</tt>: The Unix file owner group ID number. - # <tt>:mtime</tt>:: The *integer* modification time value. - # - # It will not be possible to add more than <tt>opts[:size]</tt> bytes - # to the file. - def add_file_simple(name, opts = {}) # :yields BoundedStream: - raise Archive::Tar::Minitar::BlockRequired unless block_given? - raise Archive::Tar::ClosedStream if @closed - - name, prefix = split_name(name) - - header = { :name => name, :mode => opts[:mode], :mtime => opts[:mtime], - :size => opts[:size], :gid => opts[:gid], :uid => opts[:uid], - :prefix => prefix } - header = Archive::Tar::PosixHeader.new(header).to_s - @io.write(header) - - os = BoundedStream.new(@io, opts[:size]) - yield os - # FIXME: what if an exception is raised in the block? - - min_padding = opts[:size] - os.written - @io.write("\0" * min_padding) - remainder = (512 - (opts[:size] % 512)) % 512 - @io.write("\0" * remainder) - end - - # Adds a file to the archive as +name+. +opts+ must contain the - # following value: - # - # <tt>:mode</tt>:: The Unix file permissions mode value. - # - # +opts+ may contain the following values: - # - # <tt>:uid</tt>: The Unix file owner user ID number. - # <tt>:gid</tt>: The Unix file owner group ID number. - # <tt>:mtime</tt>:: The *integer* modification time value. - # - # The file's size will be determined from the amount of data written - # to the stream. - # - # For #add_file to be used, the Archive::Tar::Minitar::Writer must be - # wrapping a stream object that is seekable (e.g., it responds to - # #pos=). Otherwise, #add_file_simple must be used. - # - # +opts+ may be modified during the writing to the stream. - def add_file(name, opts = {}) # :yields RestrictedStream, +opts+: - raise Archive::Tar::Minitar::BlockRequired unless block_given? - raise Archive::Tar::Minitar::ClosedStream if @closed - raise Archive::Tar::Minitar::NonSeekableStream unless @io.respond_to?(:pos=) - - name, prefix = split_name(name) - init_pos = @io.pos - @io.write("\0" * 512) # placeholder for the header - - yield RestrictedStream.new(@io), opts - # FIXME: what if an exception is raised in the block? - - size = @io.pos - (init_pos + 512) - remainder = (512 - (size % 512)) % 512 - @io.write("\0" * remainder) - - final_pos = @io.pos - @io.pos = init_pos - - header = { :name => name, :mode => opts[:mode], :mtime => opts[:mtime], - :size => size, :gid => opts[:gid], :uid => opts[:uid], - :prefix => prefix } - header = Archive::Tar::PosixHeader.new(header).to_s - @io.write(header) - @io.pos = final_pos - end - - # Creates a directory in the tar. - def mkdir(name, opts = {}) - raise ClosedStream if @closed - name, prefix = split_name(name) - header = { :name => name, :mode => opts[:mode], :typeflag => "5", - :size => 0, :gid => opts[:gid], :uid => opts[:uid], - :mtime => opts[:mtime], :prefix => prefix } - header = Archive::Tar::PosixHeader.new(header).to_s - @io.write(header) - nil - end - - # Passes the #flush method to the wrapped stream, used for buffered - # streams. - def flush - raise ClosedStream if @closed - @io.flush if @io.respond_to?(:flush) - end - - # Closes the Writer. - def close - return if @closed - @io.write("\0" * 1024) - @closed = true - end - - private - def split_name(name) - raise FileNameTooLong if name.size > 256 - if name.size <= 100 - prefix = "" - else - parts = name.split(/\//) - newname = parts.pop - - nxt = "" - - loop do - nxt = parts.pop - break if newname.size + 1 + nxt.size > 100 - newname = "#{nxt}/#{newname}" - end - - prefix = (parts + [nxt]).join("/") - - name = newname - - raise FileNameTooLong if name.size > 100 || prefix.size > 155 - end - return name, prefix - end - end - - # The class that reads a tar format archive from a data stream. The data - # stream may be sequential or random access, but certain features only work - # with random access data streams. - class Reader - # This marks the EntryStream closed for reading without closing the - # actual data stream. - module InvalidEntryStream - def read(len = nil); raise ClosedStream; end - def getc; raise ClosedStream; end - def rewind; raise ClosedStream; end - end - - # EntryStreams are pseudo-streams on top of the main data stream. - class EntryStream - Archive::Tar::PosixHeader::FIELDS.each do |field| - attr_reader field.intern - end - - def initialize(header, anIO) - @io = anIO - @name = header.name - @mode = header.mode - @uid = header.uid - @gid = header.gid - @size = header.size - @mtime = header.mtime - @checksum = header.checksum - @typeflag = header.typeflag - @linkname = header.linkname - @magic = header.magic - @version = header.version - @uname = header.uname - @gname = header.gname - @devmajor = header.devmajor - @devminor = header.devminor - @prefix = header.prefix - @read = 0 - @orig_pos = @io.pos - end - - # Reads +len+ bytes (or all remaining data) from the entry. Returns - # +nil+ if there is no more data to read. - def read(len = nil) - return nil if @read >= @size - len ||= @size - @read - max_read = [len, @size - @read].min - ret = @io.read(max_read) - @read += ret.size - ret - end - - # Reads one byte from the entry. Returns +nil+ if there is no more data - # to read. - def getc - return nil if @read >= @size - ret = @io.getc - @read += 1 if ret - ret - end - - # Returns +true+ if the entry represents a directory. - def directory? - @typeflag == "5" - end - alias_method :directory, :directory? - - # Returns +true+ if the entry represents a plain file. - def file? - @typeflag == "0" - end - alias_method :file, :file? - - # Returns +true+ if the current read pointer is at the end of the - # EntryStream data. - def eof? - @read >= @size - end - - # Returns the current read pointer in the EntryStream. - def pos - @read - end - - # Sets the current read pointer to the beginning of the EntryStream. - def rewind - raise NonSeekableStream unless @io.respond_to?(:pos=) - @io.pos = @orig_pos - @read = 0 - end - - def bytes_read - @read - end - - # Returns the full and proper name of the entry. - def full_name - if @prefix != "" - File.join(@prefix, @name) - else - @name - end - end - - # Closes the entry. - def close - invalidate - end - - private - def invalidate - extend InvalidEntryStream - end - end - - # With no associated block, +Reader::open+ is a synonym for - # +Reader::new+. If the optional code block is given, it will be passed - # the new _writer_ as an argument and the Reader object will - # automatically be closed when the block terminates. In this instance, - # +Reader::open+ returns the value of the block. - def self.open(anIO) - reader = Reader.new(anIO) - - return reader unless block_given? - - begin - res = yield reader - ensure - reader.close - end - - res - end - - # Creates and returns a new Reader object. - def initialize(anIO) - @io = anIO - @init_pos = anIO.pos - end - - # Iterates through each entry in the data stream. - def each(&block) - each_entry(&block) - end - - # Resets the read pointer to the beginning of data stream. Do not call - # this during a #each or #each_entry iteration. This only works with - # random access data streams that respond to #rewind and #pos. - def rewind - if @init_pos == 0 - raise NonSeekableStream unless @io.respond_to?(:rewind) - @io.rewind - else - raise NonSeekableStream unless @io.respond_to?(:pos=) - @io.pos = @init_pos - end - end - - # Iterates through each entry in the data stream. - def each_entry - loop do - return if @io.eof? - - header = Archive::Tar::PosixHeader.new_from_stream(@io) - return if header.empty? - - entry = EntryStream.new(header, @io) - size = entry.size - - yield entry - - skip = (512 - (size % 512)) % 512 - - if @io.respond_to?(:seek) - # avoid reading... - @io.seek(size - entry.bytes_read, IO::SEEK_CUR) - else - pending = size - entry.bytes_read - while pending > 0 - bread = @io.read([pending, 4096].min).size - raise UnexpectedEOF if @io.eof? - pending -= bread - end - end - @io.read(skip) # discard trailing zeros - # make sure nobody can use #read, #getc or #rewind anymore - entry.close - end - end - - def close - end - end - - # Wraps a Archive::Tar::Minitar::Reader with convenience methods and - # wrapped stream management; Input only works with random access data - # streams. See Input::new for details. - class Input - include Enumerable - - # With no associated block, +Input::open+ is a synonym for - # +Input::new+. If the optional code block is given, it will be passed - # the new _writer_ as an argument and the Input object will - # automatically be closed when the block terminates. In this instance, - # +Input::open+ returns the value of the block. - def self.open(input) - stream = Input.new(input) - return stream unless block_given? - - begin - res = yield stream - ensure - stream.close - end - - res - end - - # Creates a new Input object. If +input+ is a stream object that responds - # to #read), then it will simply be wrapped. Otherwise, one will be - # created and opened using Kernel#open. When Input#close is called, the - # stream object wrapped will be closed. - def initialize(input) - if input.respond_to?(:read) - @io = input - else - @io = open(input, "rb") - end - @tarreader = Archive::Tar::Minitar::Reader.new(@io) - end - - # Iterates through each entry and rewinds to the beginning of the stream - # when finished. - def each(&block) - @tarreader.each { |entry| yield entry } - ensure - @tarreader.rewind - end - - # Extracts the current +entry+ to +destdir+. If a block is provided, it - # yields an +action+ Symbol, the full name of the file being extracted - # (+name+), and a Hash of statistical information (+stats+). - # - # The +action+ will be one of: - # <tt>:dir</tt>:: The +entry+ is a directory. - # <tt>:file_start</tt>:: The +entry+ is a file; the extract of the - # file is just beginning. - # <tt>:file_progress</tt>:: Yielded every 4096 bytes during the extract - # of the +entry+. - # <tt>:file_done</tt>:: Yielded when the +entry+ is completed. - # - # The +stats+ hash contains the following keys: - # <tt>:current</tt>:: The current total number of bytes read in the - # +entry+. - # <tt>:currinc</tt>:: The current number of bytes read in this read - # cycle. - # <tt>:entry</tt>:: The entry being extracted; this is a - # Reader::EntryStream, with all methods thereof. - def extract_entry(destdir, entry) # :yields action, name, stats: - stats = { - :current => 0, - :currinc => 0, - :entry => entry - } - - if entry.directory? - dest = File.join(destdir, entry.full_name) - - yield :dir, entry.full_name, stats if block_given? - - if Archive::Tar::Minitar.dir?(dest) - begin - FileUtils.chmod(entry.mode, dest) - rescue Exception - nil - end - else - FileUtils.mkdir_p(dest, :mode => entry.mode) - FileUtils.chmod(entry.mode, dest) - end - - fsync_dir(dest) - fsync_dir(File.join(dest, "..")) - return - else # it's a file - destdir = File.join(destdir, File.dirname(entry.full_name)) - FileUtils.mkdir_p(destdir, :mode => 0755) - - destfile = File.join(destdir, File.basename(entry.full_name)) - FileUtils.chmod(0600, destfile) rescue nil # Errno::ENOENT - - yield :file_start, entry.full_name, stats if block_given? - - File.open(destfile, "wb", entry.mode) do |os| - loop do - data = entry.read(4096) - break unless data - - stats[:currinc] = os.write(data) - stats[:current] += stats[:currinc] - - yield :file_progress, entry.full_name, stats if block_given? - end - os.fsync - end - - FileUtils.chmod(entry.mode, destfile) - fsync_dir(File.dirname(destfile)) - fsync_dir(File.join(File.dirname(destfile), "..")) - - yield :file_done, entry.full_name, stats if block_given? - end - end - - # Returns the Reader object for direct access. - def tar - @tarreader - end - - # Closes the Reader object and the wrapped data stream. - def close - @io.close - @tarreader.close - end - - private - def fsync_dir(dirname) - # make sure this hits the disc - dir = open(dirname, 'rb') - dir.fsync - rescue # ignore IOError if it's an unpatched (old) Ruby - nil - ensure - dir.close if dir rescue nil - end - end - - # Wraps a Archive::Tar::Minitar::Writer with convenience methods and - # wrapped stream management; Output only works with random access data - # streams. See Output::new for details. - class Output - # With no associated block, +Output::open+ is a synonym for - # +Output::new+. If the optional code block is given, it will be passed - # the new _writer_ as an argument and the Output object will - # automatically be closed when the block terminates. In this instance, - # +Output::open+ returns the value of the block. - def self.open(output) - stream = Output.new(output) - return stream unless block_given? - - begin - res = yield stream - ensure - stream.close - end - - res - end - - # Creates a new Output object. If +output+ is a stream object that - # responds to #read), then it will simply be wrapped. Otherwise, one will - # be created and opened using Kernel#open. When Output#close is called, - # the stream object wrapped will be closed. - def initialize(output) - if output.respond_to?(:write) - @io = output - else - @io = ::File.open(output, "wb") - end - @tarwriter = Archive::Tar::Minitar::Writer.new(@io) - end - - # Returns the Writer object for direct access. - def tar - @tarwriter - end - - # Closes the Writer object and the wrapped data stream. - def close - @tarwriter.close - @io.close - end - end - - class << self - # Tests if +path+ refers to a directory. Fixes an apparently - # corrupted <tt>stat()</tt> call on Windows. - def dir?(path) - File.directory?((path[-1] == ?/) ? path : "#{path}/") - 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. - 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 - - # 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: - # - # <tt>:name</tt>:: The filename to be packed into the tarchive. - # *REQUIRED*. - # <tt>:mode</tt>:: The mode to be applied. - # <tt>:uid</tt>:: The user owner of the file. (Ignored on Windows.) - # <tt>:gid</tt>:: The group owner of the file. (Ignored on Windows.) - # <tt>:mtime</tt>:: 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: - # <tt>:dir</tt>:: The +entry+ is a directory. - # <tt>:file_start</tt>:: The +entry+ is a file; the extract of the - # file is just beginning. - # <tt>:file_progress</tt>:: Yielded every 4096 bytes during the extract - # of the +entry+. - # <tt>:file_done</tt>:: Yielded when the +entry+ is completed. - # - # The +stats+ hash contains the following keys: - # <tt>:current</tt>:: The current total number of bytes read in the - # +entry+. - # <tt>:currinc</tt>:: The current number of bytes read in this read - # cycle. - # <tt>:name</tt>:: The filename to be packed into the tarchive. - # *REQUIRED*. - # <tt>:mode</tt>:: The mode to be applied. - # <tt>:uid</tt>:: The user owner of the file. (+nil+ on Windows.) - # <tt>:gid</tt>:: The group owner of the file. (+nil+ on Windows.) - # <tt>:mtime</tt>:: The modification Time of the file. - 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 - - # 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. - 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 - - # A convenience method to unpack files from +src+ into the directory - # specified by +dest+. Only those files named explicitly in +files+ - # will be extracted. - 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 - end -end diff --git a/tags/version_0_5_1/minitar/lib/archive/tar/minitar/command.rb b/tags/version_0_5_1/minitar/lib/archive/tar/minitar/command.rb deleted file mode 100644 index fe9ae8b..0000000 --- a/tags/version_0_5_1/minitar/lib/archive/tar/minitar/command.rb +++ /dev/null @@ -1,814 +0,0 @@ -#!/usr/bin/env ruby -#-- -# Archive::Tar::Baby 0.5.1 -# Copyright © 2004 Mauricio Julio Fernández Pradier and Austin Ziegler -# This is free software with ABSOLUTELY NO WARRANTY. -# -# 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. -# -# This file contains an adaptation of Ruby/ProgressBar by Satoru -# Takabayashi <satoru@namazu.org>, copyright © 2001 - 2004. -# -# It is licensed under the GNU General Public Licence or Ruby's licence. -# -# $Id$ -#++ - -require 'zlib' - -# TODO: add -# TODO: delete ??? - -require 'optparse' -require 'ostruct' -require 'fileutils' - -module Archive::Tar::Minitar::Command - class ProgressBar - VERSION = "0.8" - - attr_accessor :total - attr_accessor :title - - def initialize (title, total, out = STDERR) - @title = title - @total = total - @out = out - @bar_width = 80 - @bar_mark = "o" - @current = 0 - @previous = 0 - @is_finished = false - @start_time = Time.now - @previous_time = @start_time - @title_width = 14 - @format = "%-#{@title_width}s %3d%% %s %s" - @format_arguments = [:title, :percentage, :bar, :stat] - show - end - - private - def convert_bytes (bytes) - if bytes < 1024 - sprintf("%6dB", bytes) - elsif bytes < 1024 * 1000 # 1000kb - sprintf("%5.1fKB", bytes.to_f / 1024) - elsif bytes < 1024 * 1024 * 1000 # 1000mb - sprintf("%5.1fMB", bytes.to_f / 1024 / 1024) - else - sprintf("%5.1fGB", bytes.to_f / 1024 / 1024 / 1024) - end - end - - def transfer_rate - bytes_per_second = @current.to_f / (Time.now - @start_time) - sprintf("%s/s", convert_bytes(bytes_per_second)) - end - - def bytes - convert_bytes(@current) - end - - def format_time (t) - t = t.to_i - sec = t % 60 - min = (t / 60) % 60 - hour = t / 3600 - sprintf("%02d:%02d:%02d", hour, min, sec); - end - - # ETA stands for Estimated Time of Arrival. - def eta - if @current == 0 - "ETA: --:--:--" - else - elapsed = Time.now - @start_time - eta = elapsed * @total / @current - elapsed; - sprintf("ETA: %s", format_time(eta)) - end - end - - def elapsed - elapsed = Time.now - @start_time - sprintf("Time: %s", format_time(elapsed)) - end - - def stat - if @is_finished then elapsed else eta end - end - - def stat_for_file_transfer - if @is_finished then - sprintf("%s %s %s", bytes, transfer_rate, elapsed) - else - sprintf("%s %s %s", bytes, transfer_rate, eta) - end - end - - def eol - if @is_finished then "\n" else "\r" end - end - - def bar - len = percentage * @bar_width / 100 - sprintf("|%s%s|", @bar_mark * len, " " * (@bar_width - len)) - end - - def percentage(value = nil) - if @total.zero? - 100 - else - (value || @current) * 100 / @total - end - end - - def title - @title[0,(@title_width - 1)] + ":" - end - - def get_width - # FIXME: I don't know how portable it is. - default_width = 80 - # begin - # tiocgwinsz = 0x5413 - # data = [0, 0, 0, 0].pack("SSSS") - # if @out.ioctl(tiocgwinsz, data) >= 0 then - # rows, cols, xpixels, ypixels = data.unpack("SSSS") - # if cols >= 0 then cols else default_width end - # else - # default_width - # end - # rescue Exception - # default_width - # end - end - - def show - arguments = @format_arguments.map {|method| send(method) } - line = sprintf(@format, *arguments) - - width = get_width - if line.length == width - 1 - @out.print(line + eol) - elsif line.length >= width - @bar_width = [@bar_width - (line.length - width + 1), 0].max - if @bar_width == 0 then @out.print(line + eol) else show end - else # line.length < width - 1 - @bar_width += width - line.length + 1 - show - end - @previous_time = Time.now - end - - def show_progress - if @total.zero? - cur_percentage = 100 - prev_percentage = 0 - else - cur_percentage = (@current * 100 / @total).to_i - prev_percentage = (@previous * 100 / @total).to_i - end - - if cur_percentage > prev_percentage || - Time.now - @previous_time >= 1 || - @is_finished - show - end - end - - public - def file_transfer_mode - @format_arguments = [:title, :percentage, :bar, :stat_for_file_transfer] - end - - def format= (format) - @format = format - end - - def format_arguments= (arguments) - @format_arguments = arguments - end - - def finish - @current = @total - @is_finished = true - show_progress - end - - def halt - @is_finished = true - show_progress - end - - def set (count) - if count < 0 || count > @total - raise "invalid count: #{count} (total: #{@total})" - end - @current = count - show_progress - @previous = @current - end - - def inc (step = 1) - @current += step - @current = @total if @current > @total - show_progress - @previous = @current - end - - def inspect - "(ProgressBar: #{@current}/#{@total})" - end - end - - class CommandPattern - class AbstractCommandError < Exception; end - class UnknownCommandError < RuntimeError; end - class CommandAlreadyExists < RuntimeError; end - - class << self - def add(command) - command = command.new if command.kind_of?(Class) - - @commands ||= {} - if @commands.has_key?(command.name) - raise CommandAlreadyExists - else - @commands[command.name] = command - end - - if command.respond_to?(:altname) - unless @commands.has_key?(command.altname) - @commands[command.altname] = command - end - end - end - - def <<(command) - add(command) - end - - attr_accessor :default - def default=(command) #:nodoc: - if command.kind_of?(CommandPattern) - @default = command - elsif command.kind_of?(Class) - @default = command.new - elsif @commands.has_key?(command) - @default = @commands[command] - else - raise UnknownCommandError - end - end - - def command?(command) - @commands.has_key?(command) - end - - def command(command) - if command?(command) - @commands[command] - else - @default - end - end - - def [](cmd) - self.command(cmd) - end - - def default_ioe(ioe = {}) - ioe[:input] ||= $stdin - ioe[:output] ||= $stdout - ioe[:error] ||= $stderr - ioe - end - end - - def [](args, opts = {}, ioe = {}) - call(args, opts, ioe) - end - - def name - raise AbstractCommandError - end - - def call(args, opts = {}, ioe = {}) - raise AbstractCommandError - end - - def help - raise AbstractCommandError - end - end - - class CommandHelp < CommandPattern - def name - "help" - end - - def call(args, opts = {}, ioe = {}) - ioe = CommandPattern.default_ioe(ioe) - - help_on = args.shift - - if CommandPattern.command?(help_on) - ioe[:output] << CommandPattern[help_on].help - elsif help_on == "commands" - ioe[:output] << <<-EOH -The commands known to minitar are: - - minitar create Creates a new tarfile. - minitar extract Extracts files from a tarfile. - minitar list Lists files in the tarfile. - -All commands accept the options --verbose and --progress, which are -mutually exclusive. In "minitar list", --progress means the same as ---verbose. - - --verbose, -V Performs the requested command verbosely. - --progress, -P Shows a progress bar, if appropriate, for the action - being performed. - - EOH - else - ioe[:output] << "Unknown command: #{help_on}\n" unless help_on.nil? or help_on.empty? - ioe[:output] << self.help - end - - 0 - end - - def help - help = <<-EOH -This is a basic help message containing pointers to more information on -how to use this command-line tool. Try: - - minitar help commands list all 'minitar' commands - minitar help <COMMAND> show help on <COMMAND> - (e.g., 'minitar help create') - EOH - end -# minitar add Adds a file to an existing tarfile. -# minitar delete Deletes a file from an existing tarfile. - end - - class CommandCreate < CommandPattern - def name - "create" - end - - def altname - "cr" - end - - def call(args, opts = {}, ioe = {}) - argv = [] - - while (arg = args.shift) - case arg - when '--compress', '-z' - opts[:compress] = true - else - argv << arg - end - end - - if argv.size < 2 - ioe[:output] << "Not enough arguments.\n\n" - CommandPattern["help"][["create"]] - return 255 - end - - output = argv.shift - if '-' == output - opts[:name] = "STDOUT" - output = ioe[:output] - opts[:output] = ioe[:error] - else - opts[:name] = output - output = File.open(output, "wb") - opts[:output] = ioe[:output] - end - - if opts[:name] =~ /\.tar\.gz$|\.tgz$/ or opts[:compress] - output = Zlib::GzipWriter.new(output) - end - - files = [] - if argv.include?("--") - # Read stdin for the list of files. - files = "" - files << ioe[:input].read while not ioe[:input].eof? - files = files.split(/\r\n|\n|\r/) - args.delete("--") - end - - files << argv.to_a - files.flatten! - - if opts[:verbose] - watcher = lambda do |action, name, stats| - opts[:output] << "#{name}\n" if action == :dir or action == :file_done - end - finisher = lambda { opts[:output] << "\n" } - elsif opts[:progress] - progress = ProgressBar.new(opts[:name], 1) - watcher = lambda do |action, name, stats| - case action - when :file_start, :dir - progress.title = File.basename(name) - if action == :dir - progress.total += 1 - progress.inc - else - progress.total += stats[:size] - end - when :file_progress - progress.inc(stats[:currinc]) - end - end - finisher = lambda do - progress.title = opts[:name] - progress.finish - end - else - watcher = nil - finisher = lambda { } - end - - Archive::Tar::Minitar.pack(files, output, &watcher) - finisher.call - 0 - ensure - output.close if output and not output.closed? - end - - def help - help = <<-EOH - minitar create [OPTIONS] <tarfile|-> <file|directory|-->+ - -Creates a new tarfile. If the tarfile is named .tar.gz or .tgz, then it -will be compressed automatically. If the tarfile is "-", then it will be -output to standard output (stdout) so that minitar may be piped. - -The files or directories that will be packed into the tarfile are -specified after the name of the tarfile itself. Directories will be -processed recursively. If the token "--" is found in the list of files -to be packed, additional filenames will be read from standard input -(stdin). If any file is not found, the packaging will be halted. - -create Options: - --compress, -z Compresses the tarfile with gzip. - - EOH - end - end - - class CommandExtract < CommandPattern - def name - "extract" - end - - def altname - "ex" - end - - def call(args, opts = {}, ioe = {}) - argv = [] - output = nil - dest = "." - files = [] - - while (arg = args.shift) - case arg - when '--uncompress', '-z' - opts[:uncompress] = true - when '--pipe' - opts[:output] = ioe[:error] - output = ioe[:output] - when '--output', '-o' - dest = args.shift - else - argv << arg - end - end - - if argv.size < 1 - ioe[:output] << "Not enough arguments.\n\n" - CommandPattern["help"][["extract"]] - return 255 - end - - input = argv.shift - if '-' == input - opts[:name] = "STDIN" - input = ioe[:input] - else - opts[:name] = input - input = File.open(input, "rb") - end - - if opts[:name] =~ /\.tar\.gz$|\.tgz$/ or opts[:uncompress] - input = Zlib::GzipReader.new(input) - end - - files << argv.to_a - files.flatten! - - if opts[:verbose] - watcher = lambda do |action, name, stats| - opts[:output] << "#{name}\n" if action == :dir or action == :file_done - end - finisher = lambda { opts[:output] << "\n" } - elsif opts[:progress] - progress = ProgressBar.new(opts[:name], 1) - watcher = lambda do |action, name, stats| - case action - when :file_start, :dir - progress.title = File.basename(name) - if action == :dir - progress.total += 1 - progress.inc - else - progress.total += stats[:entry].size - end - when :file_progress - progress.inc(stats[:currinc]) - end - end - finisher = lambda do - progress.title = opts[:name] - progress.finish - end - else - watcher = nil - finisher = lambda { } - end - - if output.nil? - Archive::Tar::Minitar.unpack(input, dest, files, &watcher) - finisher.call - else - Archive::Tar::Minitar::Input.open(input) do |inp| - inp.each do |entry| - stats = { - :mode => entry.mode, - :mtime => entry.mtime, - :size => entry.size, - :gid => entry.gid, - :uid => entry.uid, - :current => 0, - :currinc => 0, - :entry => entry - } - - if files.empty? or files.include?(entry.full_name) - if entry.directory? - puts "Directory: #{entry.full_name}" - watcher[:dir, dest, stats] unless watcher.nil? - else - puts "File: #{entry.full_name}" - watcher[:file_start, destfile, stats] unless watcher.nil? - loop do - data = entry.read(4096) - break unless data - stats[:currinc] = output.write(data) - stats[:current] += stats[:currinc] - - watcher[:file_progress, name, stats] unless watcher.nil? - end - watcher[:file_done, name, stats] unless watcher.nil? - end - end - end - end - end - - 0 - end - - def help - help = <<-EOH - minitar extract [OPTIONS] <tarfile|-> [<file>+] - -Extracts files from an existing tarfile. If the tarfile is named .tar.gz -or .tgz, then it will be uncompressed automatically. If the tarfile is -"-", then it will be read from standard input (stdin) so that minitar -may be piped. - -The files or directories that will be extracted from the tarfile are -specified after the name of the tarfile itself. Directories will be -processed recursively. Files must be specified in full. A file -"foo/bar/baz.txt" cannot simply be specified by specifying "baz.txt". -Any file not found will simply be skipped and an error will be reported. - -extract Options: - --uncompress, -z Uncompresses the tarfile with gzip. - --pipe Emits the extracted files to STDOUT for piping. - --output, -o Extracts the files to the specified directory. - - EOH - end - end - - class CommandList < CommandPattern - def name - "list" - end - - def altname - "ls" - end - - def modestr(mode) - s = "---" - s[0] = ?r if (mode & 4) == 4 - s[1] = ?w if (mode & 2) == 2 - s[2] = ?x if (mode & 1) == 1 - s - end - - def call(args, opts = {}, ioe = {}) - argv = [] - output = nil - dest = "." - files = [] - opts[:field] = "name" - - while (arg = args.shift) - case arg - when '--sort', '-S' - opts[:sort] = true - opts[:field] = args.shift - when '--reverse', '-R' - opts[:reverse] = true - opts[:sort] = true - when '--uncompress', '-z' - opts[:uncompress] = true - when '-l' - opts[:verbose] = true - else - argv << arg - end - end - - if argv.size < 1 - ioe[:output] << "Not enough arguments.\n\n" - CommandPattern["help"][["list"]] - return 255 - end - - input = argv.shift - if '-' == input - opts[:name] = "STDIN" - input = ioe[:input] - else - opts[:name] = input - input = File.open(input, "rb") - end - - if opts[:name] =~ /\.tar\.gz$|\.tgz$/ or opts[:uncompress] - input = Zlib::GzipReader.new(input) - end - - files << argv.to_a - files.flatten! - - if opts[:verbose] or opts[:progress] - format = "%10s %4d %8s %8s %8d %12s %s" - datefmt = "%b %d %Y" - timefmt = "%b %d %H:%M" - fields = %w(permissions inodes user group size date fullname) - else - format = "%s" - fields = %w(fullname) - end - - opts[:field] = opts[:field].intern - opts[:field] = :full_name if opts[:field] == :name - - output = [] - - Archive::Tar::Minitar::Input.open(input) do |inp| - today = Time.now - oneyear = Time.mktime(today.year - 1, today.month, today.day) - inp.each do |entry| - value = format % fields.map do |ff| - case ff - when "permissions" - s = entry.directory? ? "d" : "-" - s << modestr(entry.mode / 0100) - s << modestr(entry.mode / 0010) - s << modestr(entry.mode) - when "inodes" - entry.size / 512 - when "user" - entry.uname || entry.uid || 0 - when "group" - entry.gname || entry.gid || 0 - when "size" - entry.size - when "date" - if Time.at(entry.mtime) > (oneyear) - Time.at(entry.mtime).strftime(timefmt) - else - Time.at(entry.mtime).strftime(datefmt) - end - when "fullname" - entry.full_name - end - end - - if opts[:sort] - output << [entry.send(opts[:field]), value] - else - ioe[:output] << value << "\n" - end - - end - end - - if opts[:sort] - output = output.sort { |a, b| a[0] <=> b[0] } - if opts[:reverse] - output.reverse_each { |oo| ioe[:output] << oo[1] << "\n" } - else - output.each { |oo| ioe[:output] << oo[1] << "\n" } - end - end - - 0 - end - - def help - help = <<-EOH - minitar list [OPTIONS] <tarfile|-> [<file>+] - -Lists files in an existing tarfile. If the tarfile is named .tar.gz or -.tgz, then it will be uncompressed automatically. If the tarfile is "-", -then it will be read from standard input (stdin) so that minitar may be -piped. - -If --verbose or --progress is specified, then the file list will be -similar to that produced by the Unix command "ls -l". - -list Options: - --uncompress, -z Uncompresses the tarfile with gzip. - --sort [<FIELD>], -S Sorts the list of files by the specified - field. The sort defaults to the filename. - --reverse, -R Reverses the sort. - -l Lists the files in detail. - -Sort Fields: - name, mtime, size - - EOH - end - end - - CommandPattern << CommandHelp - CommandPattern << CommandCreate - CommandPattern << CommandExtract - CommandPattern << CommandList -# CommandPattern << CommandAdd -# CommandPattern << CommandDelete - - def self.run(argv, input = $stdin, output = $stdout, error = $stderr) - ioe = { - :input => input, - :output => output, - :error => error, - } - opts = { } - - if argv.include?("--version") - output << <<-EOB -minitar #{Archive::Tar::Minitar::VERSION} - Copyright 2004 Mauricio Julio Fernández Pradier and Austin Ziegler - This is free software with ABSOLUTELY NO WARRANTY. - - see http://rubyforge.org/projects/ruwiki for more information - EOB - end - - if argv.include?("--verbose") or argv.include?("-V") - opts[:verbose] = true - argv.delete("--verbose") - argv.delete("-V") - end - - if argv.include?("--progress") or argv.include?("-P") - opts[:progress] = true - opts[:verbose] = false - argv.delete("--progress") - argv.delete("-P") - end - - command = CommandPattern[(argv.shift or "").downcase] - command ||= CommandPattern["help"] - return command[argv, opts, ioe] - end -end diff --git a/tags/version_0_5_1/minitar/tests/tc_tar.rb b/tags/version_0_5_1/minitar/tests/tc_tar.rb deleted file mode 100644 index 542eea4..0000000 --- a/tags/version_0_5_1/minitar/tests/tc_tar.rb +++ /dev/null @@ -1,624 +0,0 @@ -#!/usr/bin/env ruby -#-- -# Ruwiki version 0.8.0 -# Copyright © 2002 - 2004, Digikata and HaloStatue -# Alan Chen (alan@digikata.com) -# Austin Ziegler (ruwiki@halostatue.ca) -# -# Licensed under the same terms as Ruby. -# -# $Id$ -#++ - -$LOAD_PATH.unshift("#{File.dirname(__FILE__)}/../lib") if __FILE__ == $0 - -require 'archive/tar/minitar' -require 'test/unit' -require 'stringio' -require 'yaml' -require 'zlib' - -module TarTester -private - def assert_headers_equal(h1, h2) - fields = %w(name 100 mode 8 uid 8 gid 8 size 12 mtime 12 checksum 8 - typeflag 1 linkname 100 magic 6 version 2 uname 32 gname 32 - devmajor 8 devminor 8 prefix 155) - offset = 0 - until fields.empty? - name = fields.shift - length = fields.shift.to_i - if name == "checksum" - chksum_off = offset - offset += length - next - end - assert_equal(h1[offset, length], h2[offset, length], - "Field #{name} of the tar header differs.") - offset += length - end - assert_equal(h1[chksum_off, 8], h2[chksum_off, 8], "Checksumes differ.") - end - - def tar_file_header(fname, dname, mode, length) - h = header("0", fname, dname, length, mode) - checksum = calc_checksum(h) - header("0", fname, dname, length, mode, checksum) - end - - def tar_dir_header(name, prefix, mode) - h = header("5", name, prefix, 0, mode) - checksum = calc_checksum(h) - header("5", name, prefix, 0, mode, checksum) - end - - def header(type, fname, dname, length, mode, checksum = nil) - checksum ||= " " * 8 - arr = [ASCIIZ(fname, 100), Z(to_oct(mode, 7)), Z(to_oct(nil, 7)), - Z(to_oct(nil, 7)), Z(to_oct(length, 11)), Z(to_oct(0, 11)), - checksum, type, "\0" * 100, "ustar\0", "00", ASCIIZ("", 32), - ASCIIZ("", 32), Z(to_oct(nil, 7)), Z(to_oct(nil, 7)), - ASCIIZ(dname, 155) ] - arr = arr.join("").split(//).map{ |x| x[0] } - h = arr.pack("C100C8C8C8C12C12C8CC100C6C2C32C32C8C8C155") - ret = h + "\0" * (512 - h.size) - assert_equal(512, ret.size) - ret - end - - def calc_checksum(header) - sum = header.unpack("C*").inject { |s, a| s + a } - SP(Z(to_oct(sum, 6))) - end - - def to_oct(n, pad_size) - if n.nil? - "\0" * pad_size - else - "%0#{pad_size}o" % n - end - end - - def ASCIIZ(str, length) - str + "\0" * (length - str.length) - end - - def SP(s) - s + " " - end - - def Z(s) - s + "\0" - end - - def SP_Z(s) - s + " \0" - end -end - -class TC_Tar__Header < Test::Unit::TestCase - include Archive::Tar::Minitar - include TarTester - - def test_arguments_are_checked - e = ArgumentError - assert_raises(e) { Archive::Tar::PosixHeader.new(:name => "", :size => "", :mode => "") } - assert_raises(e) { Archive::Tar::PosixHeader.new(:name => "", :size => "", :prefix => "") } - assert_raises(e) { Archive::Tar::PosixHeader.new(:name => "", :prefix => "", :mode => "") } - assert_raises(e) { Archive::Tar::PosixHeader.new(:prefix => "", :size => "", :mode => "") } - end - - def test_basic_headers - header = { :name => "bla", :mode => 012345, :size => 10, :prefix => "", :typeflag => "0" } - assert_headers_equal(tar_file_header("bla", "", 012345, 10), - Archive::Tar::PosixHeader.new(header).to_s) - header = { :name => "bla", :mode => 012345, :size => 0, :prefix => "", :typeflag => "5" } - assert_headers_equal(tar_dir_header("bla", "", 012345), - Archive::Tar::PosixHeader.new(header).to_s) - end - - def test_long_name_works - header = { :name => "a" * 100, :mode => 012345, :size => 10, :prefix => "" } - assert_headers_equal(tar_file_header("a" * 100, "", 012345, 10), - Archive::Tar::PosixHeader.new(header).to_s) - header = { :name => "a" * 100, :mode => 012345, :size => 10, :prefix => "bb" * 60 } - assert_headers_equal(tar_file_header("a" * 100, "bb" * 60, 012345, 10), - Archive::Tar::PosixHeader.new(header).to_s) - end - - def test_new_from_stream - header = tar_file_header("a" * 100, "", 012345, 10) - h = nil - header = StringIO.new(header) - assert_nothing_raised { h = Archive::Tar::PosixHeader.new_from_stream(header) } - assert_equal("a" * 100, h.name) - assert_equal(012345, h.mode) - assert_equal(10, h.size) - assert_equal("", h.prefix) - assert_equal("ustar", h.magic) - end - - def test_new_from_stream_with_evil_name - header = tar_file_header("a \0" + "\0" * 97, "", 012345, 10) - h = nil - header = StringIO.new(header) - assert_nothing_raised{ h = Archive::Tar::PosixHeader.new_from_stream header } - assert_equal("a ", h.name) - end -end - -class TC_Tar__Writer < Test::Unit::TestCase - include Archive::Tar::Minitar - include TarTester - - class DummyIO - attr_reader :data - - def initialize - @data = "" - end - - def write(dat) - data << dat - dat.size - end - - def reset - @data = "" - end - end - - def setup - @data = "a" * 10 - @dummyos = DummyIO.new - @os = Writer.new(@dummyos) - end - - def teardown - @os.close - end - - def test_add_file_simple - @dummyos.reset - - Writer.open(@dummyos) do |os| - os.add_file_simple("lib/foo/bar", :mode => 0644, :size => 10) do |f| - f.write "a" * 10 - end - os.add_file_simple("lib/bar/baz", :mode => 0644, :size => 100) do |f| - f.write "fillme" - end - end - - assert_headers_equal(tar_file_header("lib/foo/bar", "", 0644, 10), - @dummyos.data[0, 512]) - assert_equal("a" * 10 + "\0" * 502, @dummyos.data[512, 512]) - assert_headers_equal(tar_file_header("lib/bar/baz", "", 0644, 100), - @dummyos.data[512 * 2, 512]) - assert_equal("fillme" + "\0" * 506, @dummyos.data[512 * 3, 512]) - assert_equal("\0" * 512, @dummyos.data[512 * 4, 512]) - assert_equal("\0" * 512, @dummyos.data[512 * 5, 512]) - end - - def test_write_operations_fail_after_closed - @dummyos.reset - @os.add_file_simple("sadd", :mode => 0644, :size => 20) { |f| } - @os.close - assert_raises(ClosedStream) { @os.flush } - assert_raises(ClosedStream) { @os.add_file("dfdsf", :mode => 0644) {} } - assert_raises(ClosedStream) { @os.mkdir "sdfdsf", :mode => 0644 } - end - - def test_file_name_is_split_correctly - # test insane file lengths, and: a{100}/b{155}, etc - @dummyos.reset - names = [ "#{'a' * 155}/#{'b' * 100}", "#{'a' * 151}/#{'qwer/' * 19}bla" ] - o_names = [ "#{'b' * 100}", "#{'qwer/' * 19}bla" ] - o_prefixes = [ "a" * 155, "a" * 151 ] - names.each do |name| - @os.add_file_simple(name, :mode => 0644, :size => 10) { } - end - o_names.each_with_index do |nam, i| - assert_headers_equal(tar_file_header(nam, o_prefixes[i], 0644, 10), - @dummyos.data[2 * i * 512, 512]) - end - assert_raises(FileNameTooLong) do - @os.add_file_simple(File.join("a" * 152, "b" * 10, "a" * 92), - :mode => 0644, :size => 10) { } - end - assert_raises(FileNameTooLong) do - @os.add_file_simple(File.join("a" * 162, "b" * 10), - :mode => 0644, :size => 10) { } - end - assert_raises(FileNameTooLong) do - @os.add_file_simple(File.join("a" * 10, "b" * 110), - :mode => 0644, :size => 10) { } - end - end - - def test_add_file - dummyos = StringIO.new - class << dummyos - def method_missing(meth, *a) - self.string.send(meth, *a) - end - end - os = Writer.new dummyos - content1 = ('a'..'z').to_a.join("") # 26 - content2 = ('aa'..'zz').to_a.join("") # 1352 - Writer.open(dummyos) do |os| - os.add_file("lib/foo/bar", :mode => 0644) { |f, opts| f.write "a" * 10 } - os.add_file("lib/bar/baz", :mode => 0644) { |f, opts| f.write content1 } - os.add_file("lib/bar/baz", :mode => 0644) { |f, opts| f.write content2 } - os.add_file("lib/bar/baz", :mode => 0644) { |f, opts| } - end - assert_headers_equal(tar_file_header("lib/foo/bar", "", 0644, 10), - dummyos[0, 512]) - assert_equal(%Q(#{"a" * 10}#{"\0" * 502}), dummyos[512, 512]) - offset = 512 * 2 - [content1, content2, ""].each do |data| - assert_headers_equal(tar_file_header("lib/bar/baz", "", 0644, - data.size), dummyos[offset, 512]) - offset += 512 - until !data || data == "" - chunk = data[0, 512] - data[0, 512] = "" - assert_equal(chunk + "\0" * (512 - chunk.size), - dummyos[offset, 512]) - offset += 512 - end - end - assert_equal("\0" * 1024, dummyos[offset, 1024]) - end - - def test_add_file_tests_seekability - assert_raises(Archive::Tar::Minitar::NonSeekableStream) do - @os.add_file("libdfdsfd", :mode => 0644) { |f| } - end - end - - def test_write_header - @dummyos.reset - @os.add_file_simple("lib/foo/bar", :mode => 0644, :size => 0) { |f| } - @os.flush - assert_headers_equal(tar_file_header("lib/foo/bar", "", 0644, 0), - @dummyos.data[0, 512]) - @dummyos.reset - @os.mkdir("lib/foo", :mode => 0644) - assert_headers_equal(tar_dir_header("lib/foo", "", 0644), - @dummyos.data[0, 512]) - @os.mkdir("lib/bar", :mode => 0644) - assert_headers_equal(tar_dir_header("lib/bar", "", 0644), - @dummyos.data[512 * 1, 512]) - end - - def test_write_data - @dummyos.reset - @os.add_file_simple("lib/foo/bar", :mode => 0644, :size => 10) do |f| - f.write @data - end - @os.flush - assert_equal(@data + ("\0" * (512-@data.size)), - @dummyos.data[512, 512]) - end - - def test_file_size_is_checked - @dummyos.reset - assert_raises(Archive::Tar::Minitar::Writer::BoundedStream::FileOverflow) do - @os.add_file_simple("lib/foo/bar", :mode => 0644, :size => 10) do |f| - f.write "1" * 100 - end - end - assert_nothing_raised do - @os.add_file_simple("lib/foo/bar", :mode => 0644, :size => 10) {|f| } - end - end -end - -class TC_Tar__Reader < Test::Unit::TestCase - include Archive::Tar::Minitar - include TarTester - - def setup - end - - def teardown - end - - def test_multiple_entries - str = tar_file_header("lib/foo", "", 010644, 10) + "\0" * 512 - str += tar_file_header("bar", "baz", 0644, 0) - str += tar_dir_header("foo", "bar", 012345) - str += "\0" * 1024 - names = %w[lib/foo bar foo] - prefixes = ["", "baz", "bar"] - modes = [010644, 0644, 012345] - sizes = [10, 0, 0] - isdir = [false, false, true] - isfile = [true, true, false] - Reader.new(StringIO.new(str)) do |is| - i = 0 - is.each_entry do |entry| - assert_kind_of(Reader::EntryStream, entry) - assert_equal(names[i], entry.name) - assert_equal(prefixes[i], entry.prefix) - assert_equal(sizes[i], entry.size) - assert_equal(modes[i], entry.mode) - assert_equal(isdir[i], entry.directory?) - assert_equal(isfile[i], entry.file?) - if prefixes[i] != "" - assert_equal(File.join(prefixes[i], names[i]), entry.full_name) - else - assert_equal(names[i], entry.name) - end - i += 1 - end - assert_equal(names.size, i) - end - end - - def test_rewind_entry_works - content = ('a'..'z').to_a.join(" ") - str = tar_file_header("lib/foo", "", 010644, content.size) + content + - "\0" * (512 - content.size) - str << "\0" * 1024 - Reader.new(StringIO.new(str)) do |is| - is.each_entry do |entry| - 3.times do - entry.rewind - assert_equal(content, entry.read) - assert_equal(content.size, entry.pos) - end - end - end - end - - def test_rewind_works - content = ('a'..'z').to_a.join(" ") - str = tar_file_header("lib/foo", "", 010644, content.size) + content + - "\0" * (512 - content.size) - str << "\0" * 1024 - Reader.new(StringIO.new(str)) do |is| - 3.times do - is.rewind - i = 0 - is.each_entry do |entry| - assert_equal(content, entry.read) - i += 1 - end - assert_equal(1, i) - end - end - end - - def test_read_works - contents = ('a'..'z').inject(""){|s, x| s << x * 100} - str = tar_file_header("lib/foo", "", 010644, contents.size) + contents - str += "\0" * (512 - (str.size % 512)) - Reader.new(StringIO.new(str)) do |is| - is.each_entry do |entry| - assert_kind_of(Reader::EntryStream, entry) - data = entry.read(3000) # bigger than contents.size - assert_equal(contents, data) - assert_equal(true, entry.eof?) - end - end - Reader.new(StringIO.new(str)) do |is| - is.each_entry do |entry| - assert_kind_of(Reader::EntryStream, entry) - data = entry.read(100) - (entry.size - data.size).times {|i| data << entry.getc.chr } - assert_equal(contents, data) - assert_equal(nil, entry.read(10)) - assert_equal(true, entry.eof?) - end - end - Reader.new(StringIO.new(str)) do |is| - is.each_entry do |entry| - assert_kind_of(Reader::EntryStream, entry) - data = entry.read - assert_equal(contents, data) - assert_equal(nil, entry.read(10)) - assert_equal(nil, entry.read) - assert_equal(nil, entry.getc) - assert_equal(true, entry.eof?) - end - end - end - - def test_eof_works - str = tar_file_header("bar", "baz", 0644, 0) - Reader.new(StringIO.new(str)) do |is| - is.each_entry do |entry| - assert_kind_of(Reader::EntryStream, entry) - data = entry.read - assert_equal(nil, data) - assert_equal(nil, entry.read(10)) - assert_equal(nil, entry.read) - assert_equal(nil, entry.getc) - assert_equal(true, entry.eof?) - end - end - str = tar_dir_header("foo", "bar", 012345) - Reader.new(StringIO.new(str)) do |is| - is.each_entry do |entry| - assert_kind_of(Reader::EntryStream, entry) - data = entry.read - assert_equal(nil, data) - assert_equal(nil, entry.read(10)) - assert_equal(nil, entry.read) - assert_equal(nil, entry.getc) - assert_equal(true, entry.eof?) - end - end - str = tar_dir_header("foo", "bar", 012345) - str += tar_file_header("bar", "baz", 0644, 0) - str += tar_file_header("bar", "baz", 0644, 0) - Reader.new(StringIO.new(str)) do |is| - is.each_entry do |entry| - assert_kind_of(Reader::EntryStream, entry) - data = entry.read - assert_equal(nil, data) - assert_equal(nil, entry.read(10)) - assert_equal(nil, entry.read) - assert_equal(nil, entry.getc) - assert_equal(true, entry.eof?) - end - end - end -end - -class TC_Tar__Input < Test::Unit::TestCase - include Archive::Tar::Minitar - include TarTester - - require 'rbconfig' - - TEST_TGZ = "\037\213\010\000\001B1A\000\vKI,I\324+I,\322K\257b\240\0250\000\002sSS\254\342 `dj\306``nnnbndbjd\000\0247336`P0\240\231\213\220@i1\320\367@+\351a\327 \004\362\335\034\f\313\034\r\035\031\270\337Ns\344b2\344q\335\375M\304\266QM1W\357\321>\221U\021\005\246\306\367\356\367u3\262;\212\004\265\236\\\334}\351,\377\037;\217\223\301e\247\030\024\\\236\211\277\347\346sii\265\010\330\355\234\240\362\274\371[\202\361\366\302S\316\335o&~m\237r\355\377\303\230\365\352WNW\334\266_\373\273\237\347Q\315t?\263{\377?\006\271\337?\367\207\325\346]\371\376y\307_\234~d\3772\265\346\261}\323\317\373\315\352\377O\376\271/\305\377?X\253\324\303S\373\361\347\277\372^)\267\377\363\03460\331\311\\wW|\031\203\300@\207\325p\004i\2319\251\3064\266\203P\376702B\313\377\246\246\006&\243\371\237\036 $#\263X\001\210@\351@\301XO\201\227k\240]4\nF\301(\030\005\243\200\036\000\000\004\330t\023\000\f\000\000" - FILETIMES = Time.mktime(2004).to_i - - TEST_CONTENTS = [ - [ "data.tar.gz", 174, 0755 ], - [ "file3", 18, 0755 ], - ] - - TEST_DATA_CONTENTS = [ - [ "data", 0, 010644 ], - [ "data/file1", 16, 010644 ], - [ "data/file2", 16, 010644 ], - [ "data/__dir__", 0, 010644 ], - ] - - def setup - FileUtils.mkdir_p("data__") - end - - def teardown - FileUtils.rm_rf("data__") - end - - def test_each_works - gzr = Zlib::GzipReader.new(StringIO.new(TEST_TGZ)) - Input.open(gzr) do |is| - ii = 0 - is.each_with_index do |entry, ii| - assert_kind_of(Reader::EntryStream, entry) - assert_equal(TEST_CONTENTS[ii][0], entry.name) - assert_equal(TEST_CONTENTS[ii][1], entry.size) - assert_equal(TEST_CONTENTS[ii][2], entry.mode) - assert_equal(FILETIMES, entry.mtime) - - if 0 == ii - gzr2 = Zlib::GzipReader.new(StringIO.new(entry.read)) - Input.open(gzr2) do |is2| - jj = 0 - is2.each_with_index do |entry2, jj| - assert_kind_of(Reader::EntryStream, entry2) - assert_equal(TEST_DATA_CONTENTS[jj][0], entry2.name) - assert_equal(TEST_DATA_CONTENTS[jj][1], entry2.size) - assert_equal(TEST_DATA_CONTENTS[jj][2], entry2.mode) - assert_equal(FILETIMES, entry2.mtime) - end - assert_equal(3, jj) - end - end - end - assert_equal(1, ii) - end - end - - def test_extract_entry_works - gzr = Zlib::GzipReader.new(StringIO.new(TEST_TGZ)) - Input.open(gzr) do |is| - ii = 0 - is.each_with_index do |entry, ii| - is.extract_entry("data__", entry) - name = File.join("data__", entry.name) - - if entry.directory? - assert(File.directory?(name)) - else - assert(File.file?(name)) - - assert_equal(TEST_CONTENTS[ii][1], File.stat(name).size) - end - assert_equal(TEST_CONTENTS[ii][2], File.stat(name).mode) unless RUBY_PLATFORM =~ /win32/ - - if 0 == ii - begin - ff = File.open(name, "rb") - gzr2 = Zlib::GzipReader.new(ff) - Input.open(gzr2) do |is2| - jj = 0 - is2.each_with_index do |entry2, jj| - is2.extract_entry("data__", entry2) - name2 = File.join("data__", entry2.name) - - if entry2.directory? - assert(File.directory?(name2)) - else - assert(File.file?(name2)) - assert_equal(TEST_DATA_CONTENTS[jj][1], File.stat(name2).size, name2) - end - assert_equal(TEST_DATA_CONTENTS[jj][2], File.stat(name2).mode, name2) unless RUBY_PLATFORM =~ /win32/ - end - end - ensure - ff.close unless ff.closed? - end - end - end - assert_equal(1, ii) - end - end -end - -class TC_Tar__Output < Test::Unit::TestCase - include Archive::Tar::Minitar - include TarTester - - def setup - FileUtils.mkdir_p("data__") - %w(a b c).each do |filename| - name = File.join("data__", filename) - File.open(name, "wb") { |f| f.puts "#{name}: 123456789012345678901234567890" } - end - @tarfile = "data__/bla2.tar" - end - - def teardown - FileUtils.rm_rf("data__") - end - - def test_file_looks_good - Output.open(@tarfile) do |os| - Dir.chdir("data__") do - %w(a b c).each do |name| - stat = File.stat(name) - opts = { :size => stat.size, :mode => 0644 } - os.tar.add_file_simple(name, opts) do |ss| - File.open(name, "rb") { |ff| ss.write(ff.read(4096)) until ff.eof? } - end - end - end - end - ff = File.open(@tarfile, "rb") - Reader.open(ff) do |is| - ii = 0 - is.each do |entry| - case ii - when 0 - assert_equal("a", entry.name) - when 1 - assert_equal("b", entry.name) - when 2 - assert_equal("c", entry.name) - end - ii += 1 - end - assert_equal(3, ii) - end - ensure - ff.close if ff - end -end diff --git a/tags/version_0_5_1/minitar/tests/testall.rb b/tags/version_0_5_1/minitar/tests/testall.rb deleted file mode 100644 index 9c65d0f..0000000 --- a/tags/version_0_5_1/minitar/tests/testall.rb +++ /dev/null @@ -1,20 +0,0 @@ -#!/usr/bin/env ruby -#-- -# Ruwiki version 0.8.0 -# Copyright © 2002 - 2003, Digikata and HaloStatue -# Alan Chen (alan@digikata.com) -# Austin Ziegler (ruwiki@halostatue.ca) -# -# Licensed under the same terms as Ruby. -# -# $Id$ -#++ - -$LOAD_PATH.unshift("#{File.dirname(__FILE__)}/../lib") if __FILE__ == $0 - -puts "Checking for test cases:" -Dir['tc*.rb'].each do |testcase| - puts "\t#{testcase}" - require testcase -end -puts " " |