1# 2# = un.rb 3# 4# Copyright (c) 2003 WATANABE Hirofumi <eban@ruby-lang.org> 5# 6# This program is free software. 7# You can distribute/modify this program under the same terms of Ruby. 8# 9# == Utilities to replace common UNIX commands in Makefiles etc 10# 11# == SYNOPSIS 12# 13# ruby -run -e cp -- [OPTION] SOURCE DEST 14# ruby -run -e ln -- [OPTION] TARGET LINK_NAME 15# ruby -run -e mv -- [OPTION] SOURCE DEST 16# ruby -run -e rm -- [OPTION] FILE 17# ruby -run -e mkdir -- [OPTION] DIRS 18# ruby -run -e rmdir -- [OPTION] DIRS 19# ruby -run -e install -- [OPTION] SOURCE DEST 20# ruby -run -e chmod -- [OPTION] OCTAL-MODE FILE 21# ruby -run -e touch -- [OPTION] FILE 22# ruby -run -e wait_writable -- [OPTION] FILE 23# ruby -run -e mkmf -- [OPTION] EXTNAME [OPTION] 24# ruby -run -e httpd -- [OPTION] DocumentRoot 25# ruby -run -e help [COMMAND] 26 27require "fileutils" 28require "optparse" 29 30module FileUtils 31# @fileutils_label = "" 32 @fileutils_output = $stdout 33end 34 35def setup(options = "", *long_options) 36 opt_hash = {} 37 argv = [] 38 OptionParser.new do |o| 39 options.scan(/.:?/) do |s| 40 opt_name = s.delete(":").intern 41 o.on("-" + s.tr(":", " ")) do |val| 42 opt_hash[opt_name] = val 43 end 44 end 45 long_options.each do |s| 46 opt_name, arg_name = s.split(/(?=[\s=])/, 2) 47 opt_name.sub!(/\A--/, '') 48 s = "--#{opt_name.gsub(/([A-Z]+|[a-z])([A-Z])/, '\1-\2').downcase}#{arg_name}" 49 puts "#{opt_name}=>#{s}" if $DEBUG 50 opt_name = opt_name.intern 51 o.on(s) do |val| 52 opt_hash[opt_name] = val 53 end 54 end 55 o.on("-v") do opt_hash[:verbose] = true end 56 o.order!(ARGV) do |x| 57 if /[*?\[{]/ =~ x 58 argv.concat(Dir[x]) 59 else 60 argv << x 61 end 62 end 63 end 64 yield argv, opt_hash 65end 66 67## 68# Copy SOURCE to DEST, or multiple SOURCE(s) to DIRECTORY 69# 70# ruby -run -e cp -- [OPTION] SOURCE DEST 71# 72# -p preserve file attributes if possible 73# -r copy recursively 74# -v verbose 75# 76 77def cp 78 setup("pr") do |argv, options| 79 cmd = "cp" 80 cmd += "_r" if options.delete :r 81 options[:preserve] = true if options.delete :p 82 dest = argv.pop 83 argv = argv[0] if argv.size == 1 84 FileUtils.send cmd, argv, dest, options 85 end 86end 87 88## 89# Create a link to the specified TARGET with LINK_NAME. 90# 91# ruby -run -e ln -- [OPTION] TARGET LINK_NAME 92# 93# -s make symbolic links instead of hard links 94# -f remove existing destination files 95# -v verbose 96# 97 98def ln 99 setup("sf") do |argv, options| 100 cmd = "ln" 101 cmd += "_s" if options.delete :s 102 options[:force] = true if options.delete :f 103 dest = argv.pop 104 argv = argv[0] if argv.size == 1 105 FileUtils.send cmd, argv, dest, options 106 end 107end 108 109## 110# Rename SOURCE to DEST, or move SOURCE(s) to DIRECTORY. 111# 112# ruby -run -e mv -- [OPTION] SOURCE DEST 113# 114# -v verbose 115# 116 117def mv 118 setup do |argv, options| 119 dest = argv.pop 120 argv = argv[0] if argv.size == 1 121 FileUtils.mv argv, dest, options 122 end 123end 124 125## 126# Remove the FILE 127# 128# ruby -run -e rm -- [OPTION] FILE 129# 130# -f ignore nonexistent files 131# -r remove the contents of directories recursively 132# -v verbose 133# 134 135def rm 136 setup("fr") do |argv, options| 137 cmd = "rm" 138 cmd += "_r" if options.delete :r 139 options[:force] = true if options.delete :f 140 FileUtils.send cmd, argv, options 141 end 142end 143 144## 145# Create the DIR, if they do not already exist. 146# 147# ruby -run -e mkdir -- [OPTION] DIR 148# 149# -p no error if existing, make parent directories as needed 150# -v verbose 151# 152 153def mkdir 154 setup("p") do |argv, options| 155 cmd = "mkdir" 156 cmd += "_p" if options.delete :p 157 FileUtils.send cmd, argv, options 158 end 159end 160 161## 162# Remove the DIR. 163# 164# ruby -run -e rmdir -- [OPTION] DIR 165# 166# -p remove DIRECTORY and its ancestors. 167# -v verbose 168# 169 170def rmdir 171 setup("p") do |argv, options| 172 options[:parents] = true if options.delete :p 173 FileUtils.rmdir argv, options 174 end 175end 176 177## 178# Copy SOURCE to DEST. 179# 180# ruby -run -e install -- [OPTION] SOURCE DEST 181# 182# -p apply access/modification times of SOURCE files to 183# corresponding destination files 184# -m set permission mode (as in chmod), instead of 0755 185# -v verbose 186# 187 188def install 189 setup("pm:") do |argv, options| 190 options[:mode] = (mode = options.delete :m) ? mode.oct : 0755 191 options[:preserve] = true if options.delete :p 192 dest = argv.pop 193 argv = argv[0] if argv.size == 1 194 FileUtils.install argv, dest, options 195 end 196end 197 198## 199# Change the mode of each FILE to OCTAL-MODE. 200# 201# ruby -run -e chmod -- [OPTION] OCTAL-MODE FILE 202# 203# -v verbose 204# 205 206def chmod 207 setup do |argv, options| 208 mode = argv.shift.oct 209 FileUtils.chmod mode, argv, options 210 end 211end 212 213## 214# Update the access and modification times of each FILE to the current time. 215# 216# ruby -run -e touch -- [OPTION] FILE 217# 218# -v verbose 219# 220 221def touch 222 setup do |argv, options| 223 FileUtils.touch argv, options 224 end 225end 226 227## 228# Wait until the file becomes writable. 229# 230# ruby -run -e wait_writable -- [OPTION] FILE 231# 232# -n RETRY count to retry 233# -w SEC each wait time in seconds 234# -v verbose 235# 236 237def wait_writable 238 setup("n:w:v") do |argv, options| 239 verbose = options[:verbose] 240 n = options[:n] and n = Integer(n) 241 wait = (wait = options[:w]) ? Float(wait) : 0.2 242 argv.each do |file| 243 begin 244 open(file, "r+b") 245 rescue Errno::ENOENT 246 break 247 rescue Errno::EACCES => e 248 raise if n and (n -= 1) <= 0 249 puts e 250 STDOUT.flush 251 sleep wait 252 retry 253 end 254 end 255 end 256end 257 258## 259# Create makefile using mkmf. 260# 261# ruby -run -e mkmf -- [OPTION] EXTNAME [OPTION] 262# 263# -d ARGS run dir_config 264# -h ARGS run have_header 265# -l ARGS run have_library 266# -f ARGS run have_func 267# -v ARGS run have_var 268# -t ARGS run have_type 269# -m ARGS run have_macro 270# -c ARGS run have_const 271# --vendor install to vendor_ruby 272# 273 274def mkmf 275 setup("d:h:l:f:v:t:m:c:", "vendor") do |argv, options| 276 require 'mkmf' 277 opt = options[:d] and opt.split(/:/).each {|n| dir_config(*n.split(/,/))} 278 opt = options[:h] and opt.split(/:/).each {|n| have_header(*n.split(/,/))} 279 opt = options[:l] and opt.split(/:/).each {|n| have_library(*n.split(/,/))} 280 opt = options[:f] and opt.split(/:/).each {|n| have_func(*n.split(/,/))} 281 opt = options[:v] and opt.split(/:/).each {|n| have_var(*n.split(/,/))} 282 opt = options[:t] and opt.split(/:/).each {|n| have_type(*n.split(/,/))} 283 opt = options[:m] and opt.split(/:/).each {|n| have_macro(*n.split(/,/))} 284 opt = options[:c] and opt.split(/:/).each {|n| have_const(*n.split(/,/))} 285 $configure_args["--vendor"] = true if options[:vendor] 286 create_makefile(*argv) 287 end 288end 289 290## 291# Run WEBrick HTTP server. 292# 293# ruby -run -e httpd -- [OPTION] DocumentRoot 294# 295# --bind-address=ADDR address to bind 296# --port=NUM listening port number 297# --max-clients=MAX max number of simultaneous clients 298# --temp-dir=DIR temporary directory 299# --do-not-reverse-lookup disable reverse lookup 300# --request-timeout=SECOND request timeout in seconds 301# --http-version=VERSION HTTP version 302# -v verbose 303# 304 305def httpd 306 setup("", "BindAddress=ADDR", "Port=PORT", "MaxClients=NUM", "TempDir=DIR", 307 "DoNotReverseLookup", "RequestTimeout=SECOND", "HTTPVersion=VERSION") do 308 |argv, options| 309 require 'webrick' 310 opt = options[:RequestTimeout] and options[:RequestTimeout] = opt.to_i 311 [:Port, :MaxClients].each do |name| 312 opt = options[name] and (options[name] = Integer(opt)) rescue nil 313 end 314 unless argv.size == 1 315 raise ArgumentError, "DocumentRoot is mandatory" 316 end 317 options[:DocumentRoot] = argv.shift 318 s = WEBrick::HTTPServer.new(options) 319 shut = proc {s.shutdown} 320 siglist = %w"TERM QUIT" 321 siglist.concat(%w"HUP INT") if STDIN.tty? 322 siglist &= Signal.list.keys 323 siglist.each do |sig| 324 Signal.trap(sig, shut) 325 end 326 s.start 327 end 328end 329 330## 331# Display help message. 332# 333# ruby -run -e help [COMMAND] 334# 335 336def help 337 setup do |argv,| 338 all = argv.empty? 339 open(__FILE__) do |me| 340 while me.gets("##\n") 341 if help = me.gets("\n\n") 342 if all or argv.delete help[/-e \w+/].sub(/-e /, "") 343 print help.gsub(/^# ?/, "") 344 end 345 end 346 end 347 end 348 end 349end 350