482: def call(args, opts = {}, ioe = {})
483: argv = []
484: output = nil
485: dest = "."
486: files = []
487:
488: while (arg = args.shift)
489: case arg
490: when '--uncompress', '-z'
491: opts[:uncompress] = true
492: when '--pipe'
493: opts[:output] = ioe[:error]
494: output = ioe[:output]
495: when '--output', '-o'
496: dest = args.shift
497: else
498: argv << arg
499: end
500: end
501:
502: if argv.size < 1
503: ioe[:output] << "Not enough arguments.\n\n"
504: CommandPattern["help"][["extract"]]
505: return 255
506: end
507:
508: input = argv.shift
509: if '-' == input
510: opts[:name] = "STDIN"
511: input = ioe[:input]
512: else
513: opts[:name] = input
514: input = File.open(input, "rb")
515: end
516:
517: if opts[:name] =~ /\.tar\.gz$|\.tgz$/ or opts[:uncompress]
518: input = Zlib::GzipReader.new(input)
519: end
520:
521: files << argv.to_a
522: files.flatten!
523:
524: if opts[:verbose]
525: watcher = lambda do |action, name, stats|
526: opts[:output] << "#{name}\n" if action == :dir or action == :file_done
527: end
528: finisher = lambda { opts[:output] << "\n" }
529: elsif opts[:progress]
530: progress = ProgressBar.new(opts[:name], 1)
531: watcher = lambda do |action, name, stats|
532: case action
533: when :file_start, :dir
534: progress.title = File.basename(name)
535: if action == :dir
536: progress.total += 1
537: progress.inc
538: else
539: progress.total += stats[:entry].size
540: end
541: when :file_progress
542: progress.inc(stats[:currinc])
543: end
544: end
545: finisher = lambda do
546: progress.title = opts[:name]
547: progress.finish
548: end
549: else
550: watcher = nil
551: finisher = lambda { }
552: end
553:
554: if output.nil?
555: Archive::Tar::Minitar.unpack(input, dest, files, &watcher)
556: finisher.call
557: else
558: Archive::Tar::Minitar::Input.open(input) do |inp|
559: inp.each do |entry|
560: stats = {
561: :mode => entry.mode,
562: :mtime => entry.mtime,
563: :size => entry.size,
564: :gid => entry.gid,
565: :uid => entry.uid,
566: :current => 0,
567: :currinc => 0,
568: :entry => entry
569: }
570:
571: if files.empty? or files.include?(entry.full_name)
572: if entry.directory?
573: puts "Directory: #{entry.full_name}"
574: watcher[:dir, dest, stats] unless watcher.nil?
575: else
576: puts "File: #{entry.full_name}"
577: watcher[:file_start, destfile, stats] unless watcher.nil?
578: loop do
579: data = entry.read(4096)
580: break unless data
581: stats[:currinc] = output.write(data)
582: stats[:current] += stats[:currinc]
583:
584: watcher[:file_progress, name, stats] unless watcher.nil?
585: end
586: watcher[:file_done, name, stats] unless watcher.nil?
587: end
588: end
589: end
590: end
591: end
592:
593: 0
594: end