mirror of
https://git.FreeBSD.org/ports.git
synced 2024-12-22 04:17:44 +00:00
5d33e04596
Where appropriate fiddle with a few other things.
294 lines
5.7 KiB
Ruby
Executable File
294 lines
5.7 KiB
Ruby
Executable File
#!/usr/bin/env ruby
|
|
# -*- ruby -*-
|
|
#
|
|
# Copyright (c) 2001-2004 Akinori MUSHA
|
|
#
|
|
# All rights reserved.
|
|
#
|
|
# Redistribution and use in source and binary forms, with or without
|
|
# modification, are permitted provided that the following conditions
|
|
# are met:
|
|
# 1. Redistributions of source code must retain the above copyright
|
|
# notice, this list of conditions and the following disclaimer.
|
|
# 2. Redistributions in binary form must reproduce the above copyright
|
|
# notice, this list of conditions and the following disclaimer in the
|
|
# documentation and/or other materials provided with the distribution.
|
|
#
|
|
# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
|
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
|
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
|
# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
|
# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
|
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
|
# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
|
# SUCH DAMAGE.
|
|
|
|
RCS_ID = %q$Idaemons: /home/cvs/sunshar/sunshar.rb,v 1.13 2004/02/28 14:15:47 knu Exp $
|
|
RCS_REVISION = RCS_ID.split[2]
|
|
MYNAME = File.basename($0)
|
|
|
|
require 'optparse'
|
|
require 'fileutils'
|
|
require 'shellwords'
|
|
require 'stringio'
|
|
|
|
$USAGE = 'usage'
|
|
|
|
$strip_level = 0
|
|
$force = false
|
|
$dryrun = false
|
|
$quiet = false
|
|
$dir = nil
|
|
|
|
def info(*s)
|
|
puts(*s) unless $quiet
|
|
end
|
|
|
|
def usage
|
|
print <<-EOF
|
|
#{MYNAME} rev.#{RCS_REVISION}
|
|
|
|
usage: #{MYNAME} [-fnq] [-p level] [file]
|
|
#{MYNAME} -h
|
|
-d dir chdir -- chdir to dir before extracting files
|
|
-f force -- allow overwriting, ignore errors
|
|
-h help -- show this help
|
|
-n dry run -- show what would have been extracted
|
|
-p N strip -- strip N levels from pathnames (cf. patch(1)\'s -p)
|
|
-q quiet -- be quiet
|
|
EOF
|
|
end
|
|
|
|
def main
|
|
params = ARGV.getopts("fhnq", "d:", "p:")
|
|
|
|
if params['h']
|
|
usage
|
|
exit 0
|
|
end
|
|
|
|
if params['f']
|
|
$force = true
|
|
end
|
|
|
|
if params['n']
|
|
$dryrun = true
|
|
end
|
|
|
|
if params['q']
|
|
$quiet = true
|
|
end
|
|
|
|
$dir = params['d'] || '.'
|
|
|
|
if not params['p'].nil?
|
|
$strip_level = params['p'].to_i rescue -1
|
|
|
|
if $strip_level < 0
|
|
STDERR.puts "negative value ignored: #{params['p']}"
|
|
end
|
|
end
|
|
|
|
nerrors = 0
|
|
|
|
if ARGV.empty?
|
|
info "extracting files from stdin into #{$dir}"
|
|
|
|
begin
|
|
Dir.chdir($dir) {
|
|
unshar_stream(STDIN)
|
|
}
|
|
|
|
info "done."
|
|
rescue => e
|
|
STDERR.puts "error in extracting stdin: #{e.message}"
|
|
nerrors += 1
|
|
end
|
|
else
|
|
for file in ARGV
|
|
info "extracting files from #{file} into #{$dir}"
|
|
|
|
begin
|
|
File.open(file) do |f|
|
|
Dir.chdir($dir) {
|
|
unshar_stream(f)
|
|
}
|
|
end
|
|
|
|
info "done."
|
|
rescue => e
|
|
STDERR.puts "error in extracting #{file}: #{e.message}"
|
|
nerrors += 1
|
|
end
|
|
end
|
|
end
|
|
|
|
exit nerrors
|
|
end
|
|
|
|
def unshar_stream(io)
|
|
e = nil
|
|
|
|
while line = io.gets
|
|
if /^(\s*)\# This is a shell archive/ =~ line
|
|
indent = $1.length
|
|
break
|
|
end
|
|
end
|
|
|
|
if io.eof?
|
|
raise "not a shell archive."
|
|
end
|
|
|
|
f = nil
|
|
prefix = nil
|
|
file = nil
|
|
boundary = nil
|
|
|
|
while line = io.gets
|
|
line.slice!(0, indent)
|
|
|
|
if f
|
|
if line.strip == boundary
|
|
f.close
|
|
f = nil
|
|
next
|
|
end
|
|
|
|
if line.sub!(/^#{Regexp.quote(prefix)}/, '')
|
|
f.print line
|
|
else
|
|
raise "line #{io.lineno}: broken archive: #{line}"
|
|
end
|
|
|
|
next
|
|
end
|
|
|
|
case line
|
|
when /^exit\s*$/
|
|
break
|
|
when /^echo\s+(.+)$/
|
|
# info $1
|
|
when /^mkdir\s+(?:-p\s+)?(.+)$/
|
|
dir = nil
|
|
|
|
Shellwords.shellwords($1).each do |word|
|
|
if /^[^\-]/ =~ word
|
|
dir = word
|
|
break
|
|
end
|
|
end
|
|
|
|
next if dir.nil?
|
|
|
|
dir = strip_filename(dir.strip + '/')
|
|
if dir.chomp('/').empty?
|
|
next
|
|
end
|
|
|
|
begin
|
|
FileUtils.mkdir_p(dir) unless $dryrun
|
|
info "c - #{dir}"
|
|
rescue => e
|
|
info "c - #{dir} ... failed: #{e.message}"
|
|
raise e
|
|
end
|
|
when /sed\s+(.+)>(.+)<<(.+)/
|
|
prefix = Shellwords.shellwords($1).first
|
|
file = Shellwords.shellwords($2).first
|
|
boundary = Shellwords.shellwords($3).first
|
|
|
|
next unless prefix && file && boundary
|
|
|
|
if /s(.)\^(.*)\1\1/ =~ prefix
|
|
prefix = $2
|
|
else
|
|
next
|
|
end
|
|
|
|
file = strip_filename(file)
|
|
|
|
next if file.empty? || boundary.empty?
|
|
|
|
overwrite = false
|
|
|
|
if File.exist?(file)
|
|
if $force
|
|
overwrite = true
|
|
else
|
|
info "x - #{file} ... skipped"
|
|
next
|
|
end
|
|
end
|
|
|
|
dir = File.dirname(file)
|
|
|
|
if !File.directory?(dir + "/.")
|
|
begin
|
|
FileUtils.mkdir_p(dir) unless $dryrun
|
|
info "d - #{dir}"
|
|
rescue => e
|
|
info "d - #{dir} ... failed: #{e.message}"
|
|
raise e
|
|
end
|
|
end
|
|
|
|
begin
|
|
f = $dryrun ? StringIO.new : File.open(file, 'w')
|
|
if overwrite
|
|
info "x - #{file} ... overwritten"
|
|
else
|
|
info "x - #{file}"
|
|
end
|
|
rescue => e
|
|
info "x - #{file} ... failed! (#{e.message})"
|
|
|
|
if $force
|
|
f = nil
|
|
next
|
|
else
|
|
raise e
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
raise e if e
|
|
end
|
|
|
|
def strip_filename(file)
|
|
sfile = file.gsub(%r"/{2,}", "/")
|
|
|
|
if 0 < $strip_level
|
|
sfile.sub!(%r"^([^/]*/){1,#{$strip_level}}", '')
|
|
end
|
|
|
|
case sfile
|
|
when %r"^[~/]"
|
|
raise "reference to absolute directory: #{file} (use -p N)"
|
|
when %r"(^|/)\.\.(?:/|$)"
|
|
raise "reference to parent directory: #{file} (use -p N)"
|
|
end
|
|
|
|
sfile
|
|
end
|
|
|
|
def signal_handler(sig)
|
|
info "\nInterrupted."
|
|
|
|
exit 255
|
|
end
|
|
|
|
if $0 == __FILE__
|
|
for sig in [2, 3, 15]
|
|
trap(sig) do
|
|
signal_handler(sig)
|
|
end
|
|
end
|
|
|
|
main
|
|
end
|