summaryrefslogtreecommitdiff
path: root/lib/un.rb
diff options
context:
space:
mode:
Diffstat (limited to 'lib/un.rb')
-rw-r--r--lib/un.rb356
1 files changed, 285 insertions, 71 deletions
diff --git a/lib/un.rb b/lib/un.rb
index c665f659b1..8fb3c61a93 100644
--- a/lib/un.rb
+++ b/lib/un.rb
@@ -1,11 +1,12 @@
-#
+# frozen_string_literal: false
+#
# = un.rb
-#
+#
# Copyright (c) 2003 WATANABE Hirofumi <eban@ruby-lang.org>
-#
+#
# This program is free software.
# You can distribute/modify this program under the same terms of Ruby.
-#
+#
# == Utilities to replace common UNIX commands in Makefiles etc
#
# == SYNOPSIS
@@ -19,36 +20,55 @@
# ruby -run -e install -- [OPTION] SOURCE DEST
# ruby -run -e chmod -- [OPTION] OCTAL-MODE FILE
# ruby -run -e touch -- [OPTION] FILE
+# ruby -run -e wait_writable -- [OPTION] FILE
+# ruby -run -e mkmf -- [OPTION] EXTNAME [OPTION]
+# ruby -run -e httpd -- [OPTION] [DocumentRoot]
+# ruby -run -e colorize -- [FILE]
# ruby -run -e help [COMMAND]
-require 'fileutils'
-require 'getopts'
+require "fileutils"
+require "optparse"
module FileUtils
-# @fileutils_label = ''
@fileutils_output = $stdout
end
-def setup(options = "")
- options += "v"
- ARGV.map! do |x|
- case x
- when /^-/
- x.delete "^-#{options}"
- when /[*?\[{]/
- Dir[x]
- else
- x
+# :nodoc:
+def setup(options = "", *long_options)
+ caller = caller_locations(1, 1)[0].label
+ opt_hash = {}
+ argv = []
+ OptionParser.new do |o|
+ options.scan(/.:?/) do |s|
+ opt_name = s.delete(":").intern
+ o.on("-" + s.tr(":", " ")) do |val|
+ opt_hash[opt_name] = val
+ end
+ end
+ long_options.each do |s|
+ opt_name, arg_name = s.split(/(?=[\s=])/, 2)
+ opt_name.delete_prefix!('--')
+ s = "--#{opt_name.gsub(/([A-Z]+|[a-z])([A-Z])/, '\1-\2').downcase}#{arg_name}"
+ puts "#{opt_name}=>#{s}" if $DEBUG
+ opt_name = opt_name.intern
+ o.on(s) do |val|
+ opt_hash[opt_name] = val
+ end
+ end
+ o.on("-v") do opt_hash[:verbose] = true end
+ o.on("--help") do
+ UN.help([caller])
+ exit
+ end
+ o.order!(ARGV) do |x|
+ if /[*?\[{]/ =~ x
+ argv.concat(Dir[x])
+ else
+ argv << x
+ end
end
end
- ARGV.flatten!
- ARGV.delete_if{|x| x == '-'}
- getopts(options)
- options = {}
- options[:verbose] = true if $OPT["v"]
- options[:force] = true if $OPT["f"]
- options[:preserve] = true if $OPT["p"]
- yield ARGV, options, $OPT
+ yield argv, opt_hash
end
##
@@ -56,18 +76,21 @@ end
#
# ruby -run -e cp -- [OPTION] SOURCE DEST
#
-# -p preserve file attributes if possible
-# -r copy recursively
-# -v verbose
+# -p preserve file attributes if possible
+# -r copy recursively
+# -l make hard link instead of copying (implies -r)
+# -v verbose
#
def cp
- setup("pr") do |argv, options, opt|
+ setup("prl") do |argv, options|
cmd = "cp"
- cmd += "_r" if opt["r"]
+ cmd += "_r" if options.delete :r
+ cmd = "cp_lr" if options.delete :l
+ options[:preserve] = true if options.delete :p
dest = argv.pop
argv = argv[0] if argv.size == 1
- FileUtils.send cmd, argv, dest, options
+ FileUtils.__send__ cmd, argv, dest, **options
end
end
@@ -76,18 +99,19 @@ end
#
# ruby -run -e ln -- [OPTION] TARGET LINK_NAME
#
-# -s make symbolic links instead of hard links
-# -f remove existing destination files
-# -v verbose
+# -s make symbolic links instead of hard links
+# -f remove existing destination files
+# -v verbose
#
def ln
- setup("sf") do |argv, options, opt|
+ setup("sf") do |argv, options|
cmd = "ln"
- cmd += "_s" if opt["s"]
+ cmd += "_s" if options.delete :s
+ options[:force] = true if options.delete :f
dest = argv.pop
argv = argv[0] if argv.size == 1
- FileUtils.send cmd, argv, dest, options
+ FileUtils.__send__ cmd, argv, dest, **options
end
end
@@ -96,14 +120,14 @@ end
#
# ruby -run -e mv -- [OPTION] SOURCE DEST
#
-# -v verbose
+# -v verbose
#
def mv
setup do |argv, options|
dest = argv.pop
argv = argv[0] if argv.size == 1
- FileUtils.mv argv, dest, options
+ FileUtils.mv argv, dest, **options
end
end
@@ -112,16 +136,17 @@ end
#
# ruby -run -e rm -- [OPTION] FILE
#
-# -f ignore nonexistent files
-# -r remove the contents of directories recursively
-# -v verbose
+# -f ignore nonexistent files
+# -r remove the contents of directories recursively
+# -v verbose
#
def rm
- setup("fr") do |argv, options, opt|
+ setup("fr") do |argv, options|
cmd = "rm"
- cmd += "_r" if opt["r"]
- FileUtils.send cmd, argv, options
+ cmd += "_r" if options.delete :r
+ options[:force] = true if options.delete :f
+ FileUtils.__send__ cmd, argv, **options
end
end
@@ -130,15 +155,15 @@ end
#
# ruby -run -e mkdir -- [OPTION] DIR
#
-# -p no error if existing, make parent directories as needed
-# -v verbose
+# -p no error if existing, make parent directories as needed
+# -v verbose
#
def mkdir
- setup("p") do |argv, options, opt|
+ setup("p") do |argv, options|
cmd = "mkdir"
- cmd += "_p" if options.delete :preserve
- FileUtils.send cmd, argv, options
+ cmd += "_p" if options.delete :p
+ FileUtils.__send__ cmd, argv, **options
end
end
@@ -147,12 +172,14 @@ end
#
# ruby -run -e rmdir -- [OPTION] DIR
#
-# -v verbose
+# -p remove DIRECTORY and its ancestors.
+# -v verbose
#
def rmdir
- setup do |argv, options|
- FileUtils.rmdir argv, options
+ setup("p") do |argv, options|
+ options[:parents] = true if options.delete :p
+ FileUtils.rmdir argv, **options
end
end
@@ -161,18 +188,23 @@ end
#
# ruby -run -e install -- [OPTION] SOURCE DEST
#
-# -p apply access/modification times of SOURCE files to
-# corresponding destination files
-# -m set permission mode (as in chmod), instead of 0755
-# -v verbose
+# -p apply access/modification times of SOURCE files to
+# corresponding destination files
+# -m set permission mode (as in chmod), instead of 0755
+# -o set owner user id, instead of the current owner
+# -g set owner group id, instead of the current group
+# -v verbose
#
def install
- setup("pm:") do |argv, options, opt|
- options[:mode] = opt["m"] ? opt["m"].oct : 0755
+ setup("pm:o:g:") do |argv, options|
+ (mode = options.delete :m) and options[:mode] = /\A\d/ =~ mode ? mode.oct : mode
+ options[:preserve] = true if options.delete :p
+ (owner = options.delete :o) and options[:owner] = owner
+ (group = options.delete :g) and options[:group] = group
dest = argv.pop
argv = argv[0] if argv.size == 1
- FileUtils.install argv, dest, options
+ FileUtils.install argv, dest, **options
end
end
@@ -181,13 +213,14 @@ end
#
# ruby -run -e chmod -- [OPTION] OCTAL-MODE FILE
#
-# -v verbose
+# -v verbose
#
def chmod
setup do |argv, options|
- mode = argv.shift.oct
- FileUtils.chmod mode, argv, options
+ mode = argv.shift
+ mode = /\A\d/ =~ mode ? mode.oct : mode
+ FileUtils.chmod mode, argv, **options
end
end
@@ -196,12 +229,172 @@ end
#
# ruby -run -e touch -- [OPTION] FILE
#
-# -v verbose
+# -v verbose
#
def touch
setup do |argv, options|
- FileUtils.touch argv, options
+ FileUtils.touch argv, **options
+ end
+end
+
+##
+# Wait until the file becomes writable.
+#
+# ruby -run -e wait_writable -- [OPTION] FILE
+#
+# -n RETRY count to retry
+# -w SEC each wait time in seconds
+# -v verbose
+#
+
+def wait_writable
+ setup("n:w:v") do |argv, options|
+ verbose = options[:verbose]
+ n = options[:n] and n = Integer(n)
+ wait = (wait = options[:w]) ? Float(wait) : 0.2
+ argv.each do |file|
+ begin
+ File.open(file, "r+b") {}
+ rescue Errno::ENOENT
+ break
+ rescue Errno::EACCES => e
+ raise if n and (n -= 1) <= 0
+ if verbose
+ puts e
+ STDOUT.flush
+ end
+ sleep wait
+ retry
+ end
+ end
+ end
+end
+
+##
+# Create makefile using mkmf.
+#
+# ruby -run -e mkmf -- [OPTION] EXTNAME [OPTION]
+#
+# -d ARGS run dir_config
+# -h ARGS run have_header
+# -l ARGS run have_library
+# -f ARGS run have_func
+# -v ARGS run have_var
+# -t ARGS run have_type
+# -m ARGS run have_macro
+# -c ARGS run have_const
+# --vendor install to vendor_ruby
+#
+
+def mkmf
+ setup("d:h:l:f:v:t:m:c:", "vendor") do |argv, options|
+ require 'mkmf'
+ opt = options[:d] and opt.split(/:/).each {|n| dir_config(*n.split(/,/))}
+ opt = options[:h] and opt.split(/:/).each {|n| have_header(*n.split(/,/))}
+ opt = options[:l] and opt.split(/:/).each {|n| have_library(*n.split(/,/))}
+ opt = options[:f] and opt.split(/:/).each {|n| have_func(*n.split(/,/))}
+ opt = options[:v] and opt.split(/:/).each {|n| have_var(*n.split(/,/))}
+ opt = options[:t] and opt.split(/:/).each {|n| have_type(*n.split(/,/))}
+ opt = options[:m] and opt.split(/:/).each {|n| have_macro(*n.split(/,/))}
+ opt = options[:c] and opt.split(/:/).each {|n| have_const(*n.split(/,/))}
+ $configure_args["--vendor"] = true if options[:vendor]
+ create_makefile(*argv)
+ end
+end
+
+##
+# Run WEBrick HTTP server.
+#
+# ruby -run -e httpd -- [OPTION] [DocumentRoot]
+#
+# --bind-address=ADDR address to bind
+# --port=NUM listening port number
+# --max-clients=MAX max number of simultaneous clients
+# --temp-dir=DIR temporary directory
+# --do-not-reverse-lookup disable reverse lookup
+# --request-timeout=SECOND request timeout in seconds
+# --http-version=VERSION HTTP version
+# --server-name=NAME name of the server host
+# --server-software=NAME name and version of the server
+# --ssl-certificate=CERT The SSL certificate file for the server
+# --ssl-private-key=KEY The SSL private key file for the server certificate
+# -v verbose
+#
+
+def httpd
+ setup("", "BindAddress=ADDR", "Port=PORT", "MaxClients=NUM", "TempDir=DIR",
+ "DoNotReverseLookup", "RequestTimeout=SECOND", "HTTPVersion=VERSION",
+ "ServerName=NAME", "ServerSoftware=NAME",
+ "SSLCertificate=CERT", "SSLPrivateKey=KEY") do
+ |argv, options|
+ begin
+ require 'webrick'
+ rescue LoadError
+ abort "webrick is not found. You may need to `gem install webrick` to install webrick."
+ end
+ opt = options[:RequestTimeout] and options[:RequestTimeout] = opt.to_i
+ [:Port, :MaxClients].each do |name|
+ opt = options[name] and (options[name] = Integer(opt)) rescue nil
+ end
+ if cert = options[:SSLCertificate]
+ key = options[:SSLPrivateKey] or
+ raise "--ssl-private-key option must also be given"
+ require 'webrick/https'
+ options[:SSLEnable] = true
+ options[:SSLCertificate] = OpenSSL::X509::Certificate.new(File.read(cert))
+ options[:SSLPrivateKey] = OpenSSL::PKey.read(File.read(key))
+ options[:Port] ||= 8443 # HTTPS Alternate
+ end
+ options[:Port] ||= 8080 # HTTP Alternate
+ options[:DocumentRoot] = argv.shift || '.'
+ s = nil
+ options[:StartCallback] = proc {
+ logger = s.logger
+ logger.info("To access this server, open this URL in a browser:")
+ s.listeners.each do |listener|
+ if options[:SSLEnable]
+ addr = listener.addr
+ addr[3] = "127.0.0.1" if addr[3] == "0.0.0.0"
+ addr[3] = "::1" if addr[3] == "::"
+ logger.info(" https://#{Addrinfo.new(addr).inspect_sockaddr}")
+ else
+ logger.info(" http://#{listener.connect_address.inspect_sockaddr}")
+ end
+ end
+ }
+ s = WEBrick::HTTPServer.new(options)
+ shut = proc {s.shutdown}
+ siglist = %w"TERM QUIT"
+ siglist.concat(%w"HUP INT") if STDIN.tty?
+ siglist &= Signal.list.keys
+ siglist.each do |sig|
+ Signal.trap(sig, shut)
+ end
+ s.start
+ end
+end
+
+##
+# Colorize ruby code.
+#
+# ruby -run -e colorize -- [FILE]
+#
+
+def colorize
+ begin
+ require "irb/color"
+ rescue LoadError
+ raise "colorize requires irb 1.1.0 or later"
+ end
+ setup do |argv, |
+ if argv.empty?
+ puts IRB::Color.colorize_code STDIN.read
+ return
+ end
+ argv.each do |file|
+ puts IRB::Color.colorize_code File.read(file)
+ end
end
end
@@ -213,15 +406,36 @@ end
def help
setup do |argv,|
+ UN.help(argv)
+ end
+end
+
+module UN # :nodoc:
+
+ VERSION = "0.3.0"
+
+ module_function
+ def help(argv, output: $stdout)
all = argv.empty?
- open(__FILE__) do |me|
+ cmd = nil
+ if all
+ store = proc {|msg| output << msg}
+ else
+ messages = {}
+ store = proc {|msg| messages[cmd] = msg}
+ end
+ File.open(__FILE__) do |me|
while me.gets("##\n")
- if help = me.gets("\n\n")
- if all or argv.delete help[/-e \w+/].sub(/-e /, "")
- print help.gsub(/^# ?/, "")
- end
- end
+ if help = me.gets("\n\n")
+ if all or argv.include?(cmd = help[/^#\s*ruby\s.*-e\s+(\w+)/, 1])
+ store[help.gsub(/^# ?/, "")]
+ break unless all or argv.size > messages.size
+ end
+ end
end
end
+ if messages
+ argv.each {|arg| output << messages[arg]}
+ end
end
end