diff options
Diffstat (limited to 'lib/shell')
| -rw-r--r-- | lib/shell/builtin-command.rb | 81 | ||||
| -rw-r--r-- | lib/shell/command-processor.rb | 727 | ||||
| -rw-r--r-- | lib/shell/error.rb | 12 | ||||
| -rw-r--r-- | lib/shell/filter.rb | 102 | ||||
| -rw-r--r-- | lib/shell/process-controller.rb | 349 | ||||
| -rw-r--r-- | lib/shell/system-command.rb | 151 | ||||
| -rw-r--r-- | lib/shell/version.rb | 16 |
7 files changed, 789 insertions, 649 deletions
diff --git a/lib/shell/builtin-command.rb b/lib/shell/builtin-command.rb index 02025c5d42..e419a68c33 100644 --- a/lib/shell/builtin-command.rb +++ b/lib/shell/builtin-command.rb @@ -1,19 +1,19 @@ +# frozen_string_literal: false # -# shell/builtin-command.rb - -# $Release Version: 0.6.0 $ -# $Revision: 1.1 $ -# $Date: 2001/05/17 10:02:48 $ -# by Keiju ISHITSUKA(Nihon Rational Software Co.,Ltd) +# shell/builtin-command.rb - +# $Release Version: 0.7 $ +# $Revision$ +# by Keiju ISHITSUKA(keiju@ruby-lang.org) # # -- # -# +# # require "shell/filter" class Shell - class BuiltInCommand<Filter + class BuiltInCommand < Filter def wait? false end @@ -22,16 +22,26 @@ class Shell end end + class Void < BuiltInCommand + def initialize(sh, *opts) + super sh + end + + def each(rs = nil) + # do nothing + end + end + class Echo < BuiltInCommand def initialize(sh, *strings) super sh @strings = strings end - + def each(rs = nil) rs = @shell.record_separator unless rs for str in @strings - yield str + rs + yield str + rs end end end @@ -44,11 +54,11 @@ class Shell def each(rs = nil) if @cat_files.empty? - super + super else - for src in @cat_files - @shell.foreach(src, rs){|l| yield l} - end + for src in @cat_files + @shell.foreach(src, rs){|l| yield l} + end end end end @@ -58,39 +68,22 @@ class Shell super sh @pattern = pattern - Thread.critical = true - back = Dir.pwd - begin - Dir.chdir @shell.cwd - @files = Dir[pattern] - ensure - Dir.chdir back - Thread.critical = false - end end def each(rs = nil) + if @pattern[0] == ?/ + @files = Dir[@pattern] + else + prefix = @shell.pwd+"/" + @files = Dir[prefix+@pattern].collect{|p| p.sub(prefix, "")} + end rs = @shell.record_separator unless rs - for f in @files - yield f+rs + for f in @files + yield f+rs end end end -# class Sort < Cat -# def initialize(sh, *filenames) -# super -# end -# -# def each(rs = nil) -# ary = [] -# super{|l| ary.push l} -# for l in ary.sort! -# yield l -# end -# end -# end - class AppendIO < BuiltInCommand def initialize(sh, io, filter) super sh @@ -101,7 +94,7 @@ class Shell def input=(filter) @input.input=filter for l in @input - @io << l + @io << l end end @@ -116,9 +109,9 @@ class Shell def input=(filter) begin - super + super ensure - @io.close + @io.close end end end @@ -132,9 +125,9 @@ class Shell def each(rs = nil) to = @shell.open(@to_filename, "w") begin - super{|l| to << l; yield l} + super{|l| to << l; yield l} ensure - to.close + to.close end end end @@ -147,7 +140,7 @@ class Shell def each(rs = nil) while job = @jobs.shift - job.each{|l| yield l} + job.each{|l| yield l} end end end diff --git a/lib/shell/command-processor.rb b/lib/shell/command-processor.rb index f08440e457..08ea5c874c 100644 --- a/lib/shell/command-processor.rb +++ b/lib/shell/command-processor.rb @@ -1,18 +1,16 @@ +# frozen_string_literal: false # -# shell/command-controller.rb - -# $Release Version: 0.6.0 $ -# $Revision: 1.8.2.2 $ -# $Date: 2004/04/18 23:20:33 $ -# by Keiju ISHITSUKA(Nippon Rational Inc.) +# shell/command-controller.rb - +# $Release Version: 0.7 $ +# $Revision$ +# by Keiju ISHITSUKA(keiju@ruby-lang.org) # # -- # -# +# # require "e2mmap" -require "ftools" -require "thread" require "shell/error" require "shell/filter" @@ -20,24 +18,34 @@ require "shell/system-command" require "shell/builtin-command" class Shell + # In order to execute a command on your OS, you need to define it as a + # Shell method. + # + # Alternatively, you can execute any command via + # Shell::CommandProcessor#system even if it is not defined. class CommandProcessor -# include Error # # initialize of Shell and related classes. # - NoDelegateMethods = ["initialize", "expand_path"] + m = [:initialize, :expand_path] + if Object.methods.first.kind_of?(String) + NoDelegateMethods = m.collect{|x| x.id2name} + else + NoDelegateMethods = m + end + def self.initialize install_builtin_commands - # define CommandProccessor#methods to Shell#methods and Filter#methods + # define CommandProcessor#methods to Shell#methods and Filter#methods for m in CommandProcessor.instance_methods(false) - NoDelegateMethods - add_delegate_command_to_shell(m) + add_delegate_command_to_shell(m) end - + def self.method_added(id) - add_delegate_command_to_shell(id) + add_delegate_command_to_shell(id) end end @@ -45,15 +53,16 @@ class Shell # include run file. # def self.run_config + rc = "~/.rb_shell" begin - load File.expand_path("~/.rb_shell") if ENV.key?("HOME") + load File.expand_path(rc) if ENV.key?("HOME") rescue LoadError, Errno::ENOENT rescue - print "load error: #{rc}\n" - print $!.class, ": ", $!, "\n" - for err in $@[0, $@.size - 2] - print "\t", err, "\n" - end + print "load error: #{rc}\n" + print $!.class, ": ", $!, "\n" + for err in $@[0, $@.size - 2] + print "\t", err, "\n" + end end end @@ -64,97 +73,93 @@ class Shell # # CommandProcessor#expand_path(path) - # path: String - # return: String - # returns the absolute path for <path> + # path: String + # return: String + # returns the absolute path for <path> # def expand_path(path) @shell.expand_path(path) end + # call-seq: + # foreach(path, record_separator) -> Enumerator + # foreach(path, record_separator) { block } # - # File related commands - # Shell#foreach - # Shell#open - # Shell#unlink - # Shell#test + # See IO.foreach when +path+ is a file. # - # - - # - # CommandProcessor#foreach(path, rs) - # path: String - # rs: String - record separator - # iterator - # Same as: - # File#foreach (when path is file) - # Dir#foreach (when path is directory) - # path is relative to pwd + # See Dir.foreach when +path+ is a directory. # def foreach(path = nil, *rs) path = "." unless path path = expand_path(path) if File.directory?(path) - Dir.foreach(path){|fn| yield fn} + Dir.foreach(path){|fn| yield fn} else - IO.foreach(path, *rs){|l| yield l} + IO.foreach(path, *rs){|l| yield l} end end + # call-seq: + # open(path, mode, permissions) -> Enumerator + # open(path, mode, permissions) { block } # - # CommandProcessor#open(path, mode) - # path: String - # mode: String - # return: File or Dir - # Same as: - # File#open (when path is file) - # Dir#open (when path is directory) - # mode has an effect only when path is a file + # See IO.open when +path+ is a file. # - def open(path, mode) + # See Dir.open when +path+ is a directory. + # + def open(path, mode = nil, perm = 0666, &b) path = expand_path(path) if File.directory?(path) - Dir.open(path) + Dir.open(path, &b) else - effect_umask do - File.open(path, mode) - end + if @shell.umask + f = File.open(path, mode, perm) + File.chmod(perm & ~@shell.umask, path) + if block_given? + f.each(&b) + end + f + else + File.open(path, mode, perm, &b) + end end end - # public :open + # call-seq: + # unlink(path) + # + # See IO.unlink when +path+ is a file. # - # CommandProcessor#unlink(path) - # same as: - # Dir#unlink (when path is directory) - # File#unlink (when path is file) + # See Dir.unlink when +path+ is a directory. # def unlink(path) + @shell.check_point + path = expand_path(path) if File.directory?(path) - Dir.unlink(path) + Dir.unlink(path) else - IO.unlink(path) + IO.unlink(path) end + Void.new(@shell) end + # See Shell::CommandProcessor#test + alias top_level_test test + # call-seq: + # test(command, file1, file2) -> true or false + # [command, file1, file2] -> true or false + # + # Tests if the given +command+ exists in +file1+, or optionally +file2+. + # + # Example: + # sh[?e, "foo"] + # sh[:e, "foo"] + # sh["e", "foo"] + # sh[:exists?, "foo"] + # sh["exists?", "foo"] # - # CommandProcessor#test(command, file1, file2) - # CommandProcessor#[command, file1, file2] - # command: char or String or Symbol - # file1: String - # file2: String(optional) - # return: Boolean - # same as: - # test() (when command is char or length 1 string or symbol) - # FileTest.command (others) - # example: - # sh[?e, "foo"] - # sh[:e, "foo"] - # sh["e", "foo"] - # sh[:exists?, "foo"] - # sh["exists?", "foo"] - # def test(command, file1, file2=nil) file1 = expand_path(file1) file2 = expand_path(file2) if file2 @@ -162,110 +167,140 @@ class Shell case command when Integer - top_level_test(command, file1, file2) + if file2 + top_level_test(command, file1, file2) + else + top_level_test(command, file1) + end when String - if command.size == 1 - if file2 - top_level_test(command, file1, file2) - else - top_level_test(command, file1) - end - else - if file2 - FileTest.send(command, file1, file2) - else - FileTest.send(command, file1) - end - end + if command.size == 1 + if file2 + top_level_test(command, file1, file2) + else + top_level_test(command, file1) + end + else + unless FileTest.methods(false).include?(command.to_sym) + raise "unsupported command: #{ command }" + end + if file2 + FileTest.send(command, file1, file2) + else + FileTest.send(command, file1) + end + end end end + # See Shell::CommandProcessor#test alias [] test + # call-seq: + # mkdir(path) # - # Dir related methods - # - # Shell#mkdir - # Shell#rmdir - # - #-- - # - # CommandProcessor#mkdir(*path) - # path: String - # same as Dir.mkdir() - # + # Same as Dir.mkdir, except multiple directories are allowed. def mkdir(*path) + @shell.check_point + notify("mkdir #{path.join(' ')}") + + perm = nil + if path.last.kind_of?(Integer) + perm = path.pop + end for dir in path - Dir.mkdir(expand_path(dir)) + d = expand_path(dir) + if perm + Dir.mkdir(d, perm) + else + Dir.mkdir(d) + end + File.chmod(d, 0666 & ~@shell.umask) if @shell.umask end + Void.new(@shell) end + # call-seq: + # rmdir(path) # - # CommandProcessor#rmdir(*path) - # path: String - # same as Dir.rmdir() - # + # Same as Dir.rmdir, except multiple directories are allowed. def rmdir(*path) + @shell.check_point + notify("rmdir #{path.join(' ')}") + for dir in path - Dir.rmdir(expand_path(dir)) + Dir.rmdir(expand_path(dir)) end + Void.new(@shell) end + # call-seq: + # system(command, *options) -> SystemCommand + # + # Executes the given +command+ with the +options+ parameter. + # + # Example: + # print sh.system("ls", "-l") + # sh.system("ls", "-l") | sh.head > STDOUT # - # CommandProcessor#system(command, *opts) - # command: String - # opts: String - # return: SystemCommand - # Same as system() function - # example: - # print sh.system("ls", "-l") - # sh.system("ls", "-l") | sh.head > STDOUT - # def system(command, *opts) if opts.empty? - if command =~ /\*|\?|\{|\}|\[|\]|<|>|\(|\)|~|&|\||\\|\$|;|'|`|"|\n/ - return SystemCommand.new(@shell, find_system_command("sh"), "-c", command) - else - command, *opts = command.split(/\s+/) - end + if command =~ /\*|\?|\{|\}|\[|\]|<|>|\(|\)|~|&|\||\\|\$|;|'|`|"|\n/ + return SystemCommand.new(@shell, find_system_command("sh"), "-c", command) + else + command, *opts = command.split(/\s+/) + end end SystemCommand.new(@shell, find_system_command(command), *opts) end + # call-seq: + # rehash # - # ProcessCommand#rehash - # clear command hash table. - # + # Clears the command hash table. def rehash @system_commands = {} end - # - # ProcessCommand#transact - # - def check_point + def check_point # :nodoc: @shell.process_controller.wait_all_jobs_execution end - alias finish_all_jobs check_point + alias finish_all_jobs check_point # :nodoc: + # call-seq: + # transact { block } + # + # Executes a block as self + # + # Example: + # sh.transact { system("ls", "-l") | head > STDOUT } def transact(&block) begin - @shell.instance_eval(&block) + @shell.instance_eval(&block) ensure - check_point + check_point end end + # call-seq: + # out(device) { block } # - # internal commands - # + # Calls <code>device.print</code> on the result passing the _block_ to + # #transact def out(dev = STDOUT, &block) dev.print transact(&block) end + # call-seq: + # echo(*strings) -> Echo + # + # Returns a Echo object, for the given +strings+ def echo(*strings) Echo.new(@shell, *strings) end + # call-seq: + # cat(*filename) -> Cat + # + # Returns a Cat object, for the given +filenames+ def cat(*filenames) Cat.new(@shell, *filenames) end @@ -273,7 +308,10 @@ class Shell # def sort(*filenames) # Sort.new(self, *filenames) # end - + # call-seq: + # glob(pattern) -> Glob + # + # Returns a Glob filter object, with the given +pattern+ object def glob(pattern) Glob.new(@shell, pattern) end @@ -281,96 +319,101 @@ class Shell def append(to, filter) case to when String - AppendFile.new(@shell, to, filter) + AppendFile.new(@shell, to, filter) when IO - AppendIO.new(@shell, to, filter) + AppendIO.new(@shell, to, filter) else - Shell.Fail Error::CantApplyMethod, "append", to.class + Shell.Fail Error::CantApplyMethod, "append", to.class end end + # call-seq: + # tee(file) -> Tee + # + # Returns a Tee filter object, with the given +file+ command def tee(file) Tee.new(@shell, file) end + # call-seq: + # concat(*jobs) -> Concat + # + # Returns a Concat object, for the given +jobs+ def concat(*jobs) Concat.new(@shell, *jobs) end # %pwd, %cwd -> @pwd - def notify(*opts, &block) - Thread.exclusive do - Shell.notify(*opts) {|mes| - yield mes if iterator? - - mes.gsub!("%pwd", "#{@cwd}") - mes.gsub!("%cwd", "#{@cwd}") - } - end + def notify(*opts) + Shell.notify(*opts) {|mes| + yield mes if iterator? + + mes.gsub!("%pwd", "#{@cwd}") + mes.gsub!("%cwd", "#{@cwd}") + } end # # private functions # - def effect_umask - if @shell.umask - Thread.critical = true - save = File.umask - begin - yield - ensure - File.umask save - Thread.critical = false - end - else - yield - end - end - private :effect_umask - def find_system_command(command) return command if /^\// =~ command case path = @system_commands[command] when String - if exists?(path) - return path - else - Shell.Fail Error::CommandNotFound, command - end + if exists?(path) + return path + else + Shell.Fail Error::CommandNotFound, command + end when false - Shell.Fail Error::CommandNotFound, command + Shell.Fail Error::CommandNotFound, command end for p in @shell.system_path - path = join(p, command) - if FileTest.exists?(path) - @system_commands[command] = path - return path - end + path = join(p, command) + begin + st = File.stat(path) + rescue SystemCallError + next + else + next unless st.executable? and !st.directory? + @system_commands[command] = path + return path + end end @system_commands[command] = false Shell.Fail Error::CommandNotFound, command end + # call-seq: + # def_system_command(command, path) -> Shell::SystemCommand + # + # Defines a command, registering +path+ as a Shell method for the given + # +command+. + # + # Shell::CommandProcessor.def_system_command "ls" + # #=> Defines ls. # - # CommandProcessor.def_system_command(command, path) - # command: String - # path: String - # define 'command()' method as method. + # Shell::CommandProcessor.def_system_command "sys_sort", "sort" + # #=> Defines sys_sort as sort # def self.def_system_command(command, path = command) begin - eval((d = %Q[def #{command}(*opts) - SystemCommand.new(@shell, '#{path}', *opts) + eval((d = %Q[def #{command}(*opts) + SystemCommand.new(@shell, '#{path}', *opts) end]), nil, __FILE__, __LINE__ - 1) rescue SyntaxError - Shell.notify "warn: Can't define #{command} path: #{path}." + Shell.notify "warn: Can't define #{command} path: #{path}." end Shell.notify "Define #{command} path: #{path}.", Shell.debug? - Shell.notify("Definition of #{command}: ", d, - Shell.debug.kind_of?(Integer) && Shell.debug > 1) + Shell.notify("Definition of #{command}: ", d, + Shell.debug.kind_of?(Integer) && Shell.debug > 1) end + # call-seq: + # undef_system_command(command) -> self + # + # Undefines a command def self.undef_system_command(command) command = command.id2name if command.kind_of?(Symbol) remove_method(command) @@ -379,213 +422,249 @@ class Shell self end - # define command alias - # ex) - # def_alias_command("ls_c", "ls", "-C", "-F") - # def_alias_command("ls_c", "ls"){|*opts| ["-C", "-F", *opts]} - # @alias_map = {} + # Returns a list of aliased commands def self.alias_map @alias_map end - def self.alias_command(ali, command, *opts, &block) + # call-seq: + # alias_command(alias, command, *options) -> self + # + # Creates a command alias at the given +alias+ for the given +command+, + # passing any +options+ along with it. + # + # Shell::CommandProcessor.alias_command "lsC", "ls", "-CBF", "--show-control-chars" + # Shell::CommandProcessor.alias_command("lsC", "ls"){|*opts| ["-CBF", "--show-control-chars", *opts]} + # + def self.alias_command(ali, command, *opts) ali = ali.id2name if ali.kind_of?(Symbol) command = command.id2name if command.kind_of?(Symbol) begin - if iterator? - @alias_map[ali.intern] = proc + if iterator? + @alias_map[ali.intern] = proc - eval((d = %Q[def #{ali}(*opts) + eval((d = %Q[def #{ali}(*opts) @shell.__send__(:#{command}, *(CommandProcessor.alias_map[:#{ali}].call *opts)) - end]), nil, __FILE__, __LINE__ - 1) - - else + end]), nil, __FILE__, __LINE__ - 1) + + else args = opts.collect{|opt| '"' + opt + '"'}.join(",") eval((d = %Q[def #{ali}(*opts) @shell.__send__(:#{command}, #{args}, *opts) end]), nil, __FILE__, __LINE__ - 1) - end + end rescue SyntaxError - Shell.notify "warn: Can't alias #{ali} command: #{command}." - Shell.notify("Definition of #{ali}: ", d) - raise + Shell.notify "warn: Can't alias #{ali} command: #{command}." + Shell.notify("Definition of #{ali}: ", d) + raise end Shell.notify "Define #{ali} command: #{command}.", Shell.debug? - Shell.notify("Definition of #{ali}: ", d, - Shell.debug.kind_of?(Integer) && Shell.debug > 1) + Shell.notify("Definition of #{ali}: ", d, + Shell.debug.kind_of?(Integer) && Shell.debug > 1) self end - + + # call-seq: + # unalias_command(alias) -> self + # + # Unaliases the given +alias+ command. def self.unalias_command(ali) ali = ali.id2name if ali.kind_of?(Symbol) @alias_map.delete ali.intern undef_system_command(ali) end - - # - # CommandProcessor.def_builtin_commands(delegation_class, command_specs) - # delegation_class: Class or Module - # command_specs: [[command_name, [argument,...]],...] - # command_name: String - # arguments: String - # FILENAME?? -> expand_path(filename??) - # *FILENAME?? -> filename??.collect{|f|expand_path(f)}.join(", ") - # define command_name(argument,...) as - # delegation_class.command_name(argument,...) + + # :nodoc: + # + # Delegates File and FileTest methods into Shell, including the following + # commands: + # + # * Shell#blockdev?(file) + # * Shell#chardev?(file) + # * Shell#directory?(file) + # * Shell#executable?(file) + # * Shell#executable_real?(file) + # * Shell#exist?(file)/Shell#exists?(file) + # * Shell#file?(file) + # * Shell#grpowned?(file) + # * Shell#owned?(file) + # * Shell#pipe?(file) + # * Shell#readable?(file) + # * Shell#readable_real?(file) + # * Shell#setgid?(file) + # * Shell#setuid?(file) + # * Shell#size(file)/Shell#size?(file) + # * Shell#socket?(file) + # * Shell#sticky?(file) + # * Shell#symlink?(file) + # * Shell#writable?(file) + # * Shell#writable_real?(file) + # * Shell#zero?(file) + # * Shell#syscopy(filename_from, filename_to) + # * Shell#copy(filename_from, filename_to) + # * Shell#move(filename_from, filename_to) + # * Shell#compare(filename_from, filename_to) + # * Shell#safe_unlink(*filenames) + # * Shell#makedirs(*filenames) + # * Shell#install(filename_from, filename_to, mode) + # + # And also, there are some aliases for convenience: + # + # * Shell#cmp <- Shell#compare + # * Shell#mv <- Shell#move + # * Shell#cp <- Shell#copy + # * Shell#rm_f <- Shell#safe_unlink + # * Shell#mkpath <- Shell#makedirs # def self.def_builtin_commands(delegation_class, command_specs) for meth, args in command_specs - arg_str = args.collect{|arg| arg.downcase}.join(", ") - call_arg_str = args.collect{ - |arg| - case arg - when /^(FILENAME.*)$/ - format("expand_path(%s)", $1.downcase) - when /^(\*FILENAME.*)$/ - # \*FILENAME* -> filenames.collect{|fn| expand_path(fn)}.join(", ") - $1.downcase + '.collect{|fn| expand_path(fn)}' - else - arg - end - }.join(", ") - d = %Q[def #{meth}(#{arg_str}) - #{delegation_class}.#{meth}(#{call_arg_str}) - end] - Shell.notify "Define #{meth}(#{arg_str})", Shell.debug? - Shell.notify("Definition of #{meth}: ", d, - Shell.debug.kind_of?(Integer) && Shell.debug > 1) - eval d + arg_str = args.collect{|arg| arg.downcase}.join(", ") + call_arg_str = args.collect{ + |arg| + case arg + when /^(FILENAME.*)$/ + format("expand_path(%s)", $1.downcase) + when /^(\*FILENAME.*)$/ + # \*FILENAME* -> filenames.collect{|fn| expand_path(fn)}.join(", ") + $1.downcase + '.collect{|fn| expand_path(fn)}' + else + arg + end + }.join(", ") + d = %Q[def #{meth}(#{arg_str}) + #{delegation_class}.#{meth}(#{call_arg_str}) + end] + Shell.notify "Define #{meth}(#{arg_str})", Shell.debug? + Shell.notify("Definition of #{meth}: ", d, + Shell.debug.kind_of?(Integer) && Shell.debug > 1) + eval d end end + # call-seq: + # install_system_commands(prefix = "sys_") + # + # Defines all commands in the Shell.default_system_path as Shell method, + # all with given +prefix+ appended to their names. # - # CommandProcessor.install_system_commands(pre) - # pre: String - command name prefix - # defines every command which belongs in default_system_path via - # CommandProcessor.command(). It doesn't define already defined - # methods twice. By default, "pre_" is prefixes to each method - # name. Characters that may not be used in a method name are - # all converted to '_'. Definition errors are just ignored. + # Any invalid character names are converted to +_+, and errors are passed + # to Shell.notify. # + # Methods already defined are skipped. def self.install_system_commands(pre = "sys_") defined_meth = {} for m in Shell.methods - defined_meth[m] = true + defined_meth[m] = true end sh = Shell.new for path in Shell.default_system_path - next unless sh.directory? path - sh.cd path - sh.foreach do - |cn| - if !defined_meth[pre + cn] && sh.file?(cn) && sh.executable?(cn) - command = (pre + cn).gsub(/\W/, "_").sub(/^([0-9])/, '_\1') - begin - def_system_command(command, sh.expand_path(cn)) - rescue - Shell.notify "warn: Can't define #{command} path: #{cn}" - end - defined_meth[command] = command - end - end + next unless sh.directory? path + sh.cd path + sh.foreach do + |cn| + if !defined_meth[pre + cn] && sh.file?(cn) && sh.executable?(cn) + command = (pre + cn).gsub(/\W/, "_").sub(/^([0-9])/, '_\1') + begin + def_system_command(command, sh.expand_path(cn)) + rescue + Shell.notify "warn: Can't define #{command} path: #{cn}" + end + defined_meth[command] = command + end + end end end - #---------------------------------------------------------------------- - # - # class initializing methods - - # - #---------------------------------------------------------------------- - def self.add_delegate_command_to_shell(id) + def self.add_delegate_command_to_shell(id) # :nodoc: id = id.intern if id.kind_of?(String) name = id.id2name if Shell.method_defined?(id) - Shell.notify "warn: override definnition of Shell##{name}." - Shell.notify "warn: alias Shell##{name} to Shell##{name}_org.\n" - Shell.module_eval "alias #{name}_org #{name}" + Shell.notify "warn: override definition of Shell##{name}." + Shell.notify "warn: alias Shell##{name} to Shell##{name}_org.\n" + Shell.module_eval "alias #{name}_org #{name}" end Shell.notify "method added: Shell##{name}.", Shell.debug? Shell.module_eval(%Q[def #{name}(*args, &block) - begin - @command_processor.__send__(:#{name}, *args, &block) - rescue Exception - $@.delete_if{|s| /:in `__getobj__'$/ =~ s} #` - $@.delete_if{|s| /^\\(eval\\):/ =~ s} - raise - end + begin + @command_processor.__send__(:#{name}, *args, &block) + rescue Exception + $@.delete_if{|s| /:in `__getobj__'$/ =~ s} #` + $@.delete_if{|s| /^\\(eval\\):/ =~ s} + raise + end end], __FILE__, __LINE__) if Shell::Filter.method_defined?(id) - Shell.notify "warn: override definnition of Shell::Filter##{name}." - Shell.notify "warn: alias Shell##{name} to Shell::Filter##{name}_org." - Filter.module_eval "alias #{name}_org #{name}" + Shell.notify "warn: override definition of Shell::Filter##{name}." + Shell.notify "warn: alias Shell##{name} to Shell::Filter##{name}_org." + Filter.module_eval "alias #{name}_org #{name}" end Shell.notify "method added: Shell::Filter##{name}.", Shell.debug? Filter.module_eval(%Q[def #{name}(*args, &block) - begin - self | @shell.__send__(:#{name}, *args, &block) - rescue Exception - $@.delete_if{|s| /:in `__getobj__'$/ =~ s} #` - $@.delete_if{|s| /^\\(eval\\):/ =~ s} - raise - end + begin + self | @shell.__send__(:#{name}, *args, &block) + rescue Exception + $@.delete_if{|s| /:in `__getobj__'$/ =~ s} #` + $@.delete_if{|s| /^\\(eval\\):/ =~ s} + raise + end end], __FILE__, __LINE__) end - # - # define default builtin commands + # Delegates File methods into Shell, including the following commands: + # + # * Shell#atime(file) + # * Shell#basename(file, *opt) + # * Shell#chmod(mode, *files) + # * Shell#chown(owner, group, *file) + # * Shell#ctime(file) + # * Shell#delete(*file) + # * Shell#dirname(file) + # * Shell#ftype(file) + # * Shell#join(*file) + # * Shell#link(file_from, file_to) + # * Shell#lstat(file) + # * Shell#mtime(file) + # * Shell#readlink(file) + # * Shell#rename(file_from, file_to) + # * Shell#split(file) + # * Shell#stat(file) + # * Shell#symlink(file_from, file_to) + # * Shell#truncate(file, length) + # * Shell#utime(atime, mtime, *file) # def self.install_builtin_commands # method related File. - # (exclude open/foreach/unlink) + # (exclude open/foreach/unlink) normal_delegation_file_methods = [ - ["atime", ["FILENAME"]], - ["basename", ["fn", "*opts"]], - ["chmod", ["mode", "*FILENAMES"]], - ["chown", ["owner", "group", "*FILENAME"]], - ["ctime", ["FILENAMES"]], - ["delete", ["*FILENAMES"]], - ["dirname", ["FILENAME"]], - ["ftype", ["FILENAME"]], - ["join", ["*items"]], - ["link", ["FILENAME_O", "FILENAME_N"]], - ["lstat", ["FILENAME"]], - ["mtime", ["FILENAME"]], - ["readlink", ["FILENAME"]], - ["rename", ["FILENAME_FROM", "FILENAME_TO"]], - # ["size", ["FILENAME"]], - ["split", ["pathname"]], - ["stat", ["FILENAME"]], - ["symlink", ["FILENAME_O", "FILENAME_N"]], - ["truncate", ["FILENAME", "length"]], - ["utime", ["atime", "mtime", "*FILENAMES"]]] + ["atime", ["FILENAME"]], + ["basename", ["fn", "*opts"]], + ["chmod", ["mode", "*FILENAMES"]], + ["chown", ["owner", "group", "*FILENAME"]], + ["ctime", ["FILENAMES"]], + ["delete", ["*FILENAMES"]], + ["dirname", ["FILENAME"]], + ["ftype", ["FILENAME"]], + ["join", ["*items"]], + ["link", ["FILENAME_O", "FILENAME_N"]], + ["lstat", ["FILENAME"]], + ["mtime", ["FILENAME"]], + ["readlink", ["FILENAME"]], + ["rename", ["FILENAME_FROM", "FILENAME_TO"]], + ["split", ["pathname"]], + ["stat", ["FILENAME"]], + ["symlink", ["FILENAME_O", "FILENAME_N"]], + ["truncate", ["FILENAME", "length"]], + ["utime", ["atime", "mtime", "*FILENAMES"]]] def_builtin_commands(File, normal_delegation_file_methods) alias_method :rm, :delete # method related FileTest - def_builtin_commands(FileTest, - FileTest.singleton_methods(false).collect{|m| [m, ["FILENAME"]]}) - - # method related ftools - normal_delegation_ftools_methods = [ - ["syscopy", ["FILENAME_FROM", "FILENAME_TO"]], - ["copy", ["FILENAME_FROM", "FILENAME_TO"]], - ["move", ["FILENAME_FROM", "FILENAME_TO"]], - ["compare", ["FILENAME_FROM", "FILENAME_TO"]], - ["safe_unlink", ["*FILENAMES"]], - ["makedirs", ["*FILENAMES"]], - # ["chmod", ["mode", "*FILENAMES"]], - ["install", ["FILENAME_FROM", "FILENAME_TO", "mode"]], - ] - def_builtin_commands(File, - normal_delegation_ftools_methods) - alias_method :cmp, :compare - alias_method :mv, :move - alias_method :cp, :copy - alias_method :rm_f, :safe_unlink - alias_method :mkpath, :makedirs + def_builtin_commands(FileTest, + FileTest.singleton_methods(false).collect{|m| [m, ["FILENAME"]]}) + end end diff --git a/lib/shell/error.rb b/lib/shell/error.rb index 2f176862a8..677c424baf 100644 --- a/lib/shell/error.rb +++ b/lib/shell/error.rb @@ -1,13 +1,13 @@ +# frozen_string_literal: false # -# shell/error.rb - -# $Release Version: 0.6.0 $ -# $Revision: 1.2 $ -# $Date: 2003/02/07 19:00:21 $ -# by Keiju ISHITSUKA(Nihon Rational Software Co.,Ltd) +# shell/error.rb - +# $Release Version: 0.7 $ +# $Revision$ +# by Keiju ISHITSUKA(keiju@ruby-lang.org) # # -- # -# +# # require "e2mmap" diff --git a/lib/shell/filter.rb b/lib/shell/filter.rb index 12cc5206f8..caa976ae3e 100644 --- a/lib/shell/filter.rb +++ b/lib/shell/filter.rb @@ -1,27 +1,28 @@ +# frozen_string_literal: false # -# shell/filter.rb - -# $Release Version: 0.6.0 $ -# $Revision: 1.3.2.1 $ -# $Date: 2004/03/21 12:21:11 $ -# by Keiju ISHITSUKA(Nihon Rational Software Co.,Ltd) +# shell/filter.rb - +# $Release Version: 0.7 $ +# $Revision$ +# by Keiju ISHITSUKA(keiju@ruby-lang.org) # # -- # -# +# # -class Shell +class Shell #:nodoc: + # Any result of command execution is a Filter. # - # Filter - # A method to require - # each() + # This class includes Enumerable, therefore a Filter object can use all + # Enumerable + # facilities. # class Filter include Enumerable def initialize(sh) - @shell = sh # parent shell - @input = nil # input filter + @shell = sh # parent shell + @input = nil # input filter end attr_reader :input @@ -29,61 +30,88 @@ class Shell def input=(filter) @input = filter end - + + # call-seq: + # each(record_separator=nil) { block } + # + # Iterates a block for each line. def each(rs = nil) rs = @shell.record_separator unless rs if @input - @input.each(rs){|l| yield l} + @input.each(rs){|l| yield l} end end - def < (src) + # call-seq: + # < source + # + # Inputs from +source+, which is either a string of a file name or an IO + # object. + def <(src) case src when String - cat = Cat.new(@shell, src) - cat | self + cat = Cat.new(@shell, src) + cat | self when IO - self.input = src - self + self.input = src + self else - Shell.Fail Error::CantApplyMethod, "<", to.class + Shell.Fail Error::CantApplyMethod, "<", src.class end end - def > (to) + # call-seq: + # > source + # + # Outputs from +source+, which is either a string of a file name or an IO + # object. + def >(to) case to when String - dst = @shell.open(to, "w") - begin - each(){|l| dst << l} - ensure - dst.close - end + dst = @shell.open(to, "w") + begin + each(){|l| dst << l} + ensure + dst.close + end when IO - each(){|l| to << l} + each(){|l| to << l} else - Shell.Fail Error::CantApplyMethod, ">", to.class + Shell.Fail Error::CantApplyMethod, ">", to.class end self end - def >> (to) + # call-seq: + # >> source + # + # Appends the output to +source+, which is either a string of a file name + # or an IO object. + def >>(to) begin - Shell.cd(@shell.pwd).append(to, self) + Shell.cd(@shell.pwd).append(to, self) rescue CantApplyMethod - Shell.Fail Error::CantApplyMethod, ">>", to.class + Shell.Fail Error::CantApplyMethod, ">>", to.class end end - def | (filter) + # call-seq: + # | filter + # + # Processes a pipeline. + def |(filter) filter.input = self if active? - @shell.process_controller.start_job filter + @shell.process_controller.start_job filter end filter end - def + (filter) + # call-seq: + # filter1 + filter2 + # + # Outputs +filter1+, and then +filter2+ using Join.new + def +(filter) Join.new(@shell, self, filter) end @@ -101,9 +129,9 @@ class Shell def inspect if @shell.debug.kind_of?(Integer) && @shell.debug > 2 - super + super else - to_s + to_s end end end diff --git a/lib/shell/process-controller.rb b/lib/shell/process-controller.rb index 573edb6829..d54da68cb0 100644 --- a/lib/shell/process-controller.rb +++ b/lib/shell/process-controller.rb @@ -1,77 +1,111 @@ +# frozen_string_literal: false # -# shell/process-controller.rb - -# $Release Version: 0.6.0 $ -# $Revision: 1.3 $ -# $Date: 2003/10/16 17:47:19 $ -# by Keiju ISHITSUKA(Nihon Rational Software Co.,Ltd) +# shell/process-controller.rb - +# $Release Version: 0.7 $ +# $Revision$ +# by Keiju ISHITSUKA(keiju@ruby-lang.org) # # -- # -# # - -require "mutex_m" -require "monitor" +# +require "forwardable" require "sync" class Shell class ProcessController @ProcessControllers = {} - @ProcessControllers.extend Mutex_m + @ProcessControllersMonitor = Thread::Mutex.new + @ProcessControllersCV = Thread::ConditionVariable.new + + @BlockOutputMonitor = Thread::Mutex.new + @BlockOutputCV = Thread::ConditionVariable.new + + class << self + extend Forwardable - class<<self + def_delegator("@ProcessControllersMonitor", + "synchronize", "process_controllers_exclusive") - def process_controllers_exclusive - begin - @ProcessControllers.lock unless Thread.critical - yield - ensure - @ProcessControllers.unlock unless Thread.critical - end + def active_process_controllers + process_controllers_exclusive do + @ProcessControllers.dup + end end def activate(pc) - process_controllers_exclusive do - @ProcessControllers[pc] ||= 0 - @ProcessControllers[pc] += 1 - end + process_controllers_exclusive do + @ProcessControllers[pc] ||= 0 + @ProcessControllers[pc] += 1 + end end def inactivate(pc) - process_controllers_exclusive do - if @ProcessControllers[pc] - if (@ProcessControllers[pc] -= 1) == 0 - @ProcessControllers.delete(pc) - end - end - end + process_controllers_exclusive do + if @ProcessControllers[pc] + if (@ProcessControllers[pc] -= 1) == 0 + @ProcessControllers.delete(pc) + @ProcessControllersCV.signal + end + end + end end def each_active_object - process_controllers_exclusive do - for ref in @ProcessControllers.keys - yield ref - end - end + process_controllers_exclusive do + for ref in @ProcessControllers.keys + yield ref + end + end + end + + def block_output_synchronize(&b) + @BlockOutputMonitor.synchronize(&b) + end + + def wait_to_finish_all_process_controllers + process_controllers_exclusive do + while !@ProcessControllers.empty? + Shell::notify("Process finishing, but active shell exists", + "You can use Shell#transact or Shell#check_point for more safe execution.") + if Shell.debug? + for pc in @ProcessControllers.keys + Shell::notify(" Not finished jobs in "+pc.shell.to_s) + for com in pc.jobs + com.notify(" Jobs: %id") + end + end + end + @ProcessControllersCV.wait(@ProcessControllersMonitor) + end + end end end + # for shell-command complete finish at this process exit. + USING_AT_EXIT_WHEN_PROCESS_EXIT = true + at_exit do + wait_to_finish_all_process_controllers unless $@ + end + def initialize(shell) @shell = shell @waiting_jobs = [] @active_jobs = [] @jobs_sync = Sync.new - @job_monitor = Mutex.new - @job_condition = ConditionVariable.new + @job_monitor = Thread::Mutex.new + @job_condition = Thread::ConditionVariable.new end + attr_reader :shell + def jobs jobs = [] @jobs_sync.synchronize(:SH) do - jobs.concat @waiting_jobs - jobs.concat @active_jobs + jobs.concat @waiting_jobs + jobs.concat @active_jobs end jobs end @@ -83,177 +117,192 @@ class Shell def waiting_jobs @waiting_jobs end - + def jobs_exist? @jobs_sync.synchronize(:SH) do - @active_jobs.empty? or @waiting_jobs.empty? + @active_jobs.empty? or @waiting_jobs.empty? end end def active_jobs_exist? @jobs_sync.synchronize(:SH) do - @active_jobs.empty? + @active_jobs.empty? end end def waiting_jobs_exist? @jobs_sync.synchronize(:SH) do - @waiting_jobs.empty? + @waiting_jobs.empty? end end # schedule a command def add_schedule(command) @jobs_sync.synchronize(:EX) do - ProcessController.activate(self) - if @active_jobs.empty? - start_job command - else - @waiting_jobs.push(command) - end + ProcessController.activate(self) + if @active_jobs.empty? + start_job command + else + @waiting_jobs.push(command) + end end end # start a job def start_job(command = nil) @jobs_sync.synchronize(:EX) do - if command - return if command.active? - @waiting_jobs.delete command - else - command = @waiting_jobs.shift - return unless command - end - @active_jobs.push command - command.start - - # start all jobs that input from the job - for job in @waiting_jobs - start_job(job) if job.input == command - end + if command + return if command.active? + @waiting_jobs.delete command + else + command = @waiting_jobs.shift + + return unless command + end + @active_jobs.push command + command.start + + # start all jobs that input from the job + for job in @waiting_jobs.dup + start_job(job) if job.input == command + end end end def waiting_job?(job) @jobs_sync.synchronize(:SH) do - @waiting_jobs.include?(job) + @waiting_jobs.include?(job) end end def active_job?(job) @jobs_sync.synchronize(:SH) do - @active_jobs.include?(job) + @active_jobs.include?(job) end end # terminate a job def terminate_job(command) @jobs_sync.synchronize(:EX) do - @active_jobs.delete command - ProcessController.inactivate(self) - if @active_jobs.empty? - start_job - end + @active_jobs.delete command + ProcessController.inactivate(self) + if @active_jobs.empty? + command.notify("start_job in terminate_job(%id)", Shell::debug?) + start_job + end end end # kill a job def kill_job(sig, command) - @jobs_sync.synchronize(:SH) do - if @waiting_jobs.delete command - ProcessController.inactivate(self) - return - elsif @active_jobs.include?(command) - begin - r = command.kill(sig) - ProcessController.inactivate(self) - rescue - print "Shell: Warn: $!\n" if @shell.verbose? - return nil - end - @active_jobs.delete command - r - end + @jobs_sync.synchronize(:EX) do + if @waiting_jobs.delete command + ProcessController.inactivate(self) + return + elsif @active_jobs.include?(command) + begin + r = command.kill(sig) + ProcessController.inactivate(self) + rescue + print "Shell: Warn: $!\n" if @shell.verbose? + return nil + end + @active_jobs.delete command + r + end end end # wait for all jobs to terminate def wait_all_jobs_execution @job_monitor.synchronize do - begin - while !jobs.empty? - @job_condition.wait(@job_monitor) - end - ensure - redo unless jobs.empty? - end + begin + while !jobs.empty? + @job_condition.wait(@job_monitor) + for job in jobs + job.notify("waiting job(%id)", Shell::debug?) + end + end + ensure + redo unless jobs.empty? + end end end # simple fork - def sfork(command, &block) + def sfork(command) pipe_me_in, pipe_peer_out = IO.pipe pipe_peer_in, pipe_me_out = IO.pipe - Thread.critical = true - STDOUT.flush - ProcessController.each_active_object do |pc| - for jobs in pc.active_jobs - jobs.flush - end + + pid = nil + pid_mutex = Thread::Mutex.new + pid_cv = Thread::ConditionVariable.new + + Thread.start do + ProcessController.block_output_synchronize do + STDOUT.flush + ProcessController.each_active_object do |pc| + for jobs in pc.active_jobs + jobs.flush + end + end + + pid = fork { + Thread.list.each do |th| + th.kill unless Thread.current == th + end + + STDIN.reopen(pipe_peer_in) + STDOUT.reopen(pipe_peer_out) + + ObjectSpace.each_object(IO) do |io| + if ![STDIN, STDOUT, STDERR].include?(io) + io.close + end + end + + yield + } + end + pid_cv.signal + + pipe_peer_in.close + pipe_peer_out.close + command.notify "job(%name:##{pid}) start", @shell.debug? + + begin + _pid = nil + command.notify("job(%id) start to waiting finish.", @shell.debug?) + _pid = Process.waitpid(pid, nil) + rescue Errno::ECHILD + command.notify "warn: job(%id) was done already waitpid." + _pid = true + ensure + command.notify("Job(%id): Wait to finish when Process finished.", @shell.debug?) + # when the process ends, wait until the command terminates + if USING_AT_EXIT_WHEN_PROCESS_EXIT or _pid + else + command.notify("notice: Process finishing...", + "wait for Job[%id] to finish.", + "You can use Shell#transact or Shell#check_point for more safe execution.") + redo + end + + @job_monitor.synchronize do + terminate_job(command) + @job_condition.signal + command.notify "job(%id) finish.", @shell.debug? + end + end end - - pid = fork { - Thread.critical = true - - Thread.list.each do |th| - th.kill unless [Thread.main, Thread.current].include?(th) - end - - STDIN.reopen(pipe_peer_in) - STDOUT.reopen(pipe_peer_out) - - ObjectSpace.each_object(IO) do |io| - if ![STDIN, STDOUT, STDERR].include?(io) - io.close unless io.closed? - end - end - yield - } - - pipe_peer_in.close - pipe_peer_out.close - command.notify "job(%name:##{pid}) start", @shell.debug? - Thread.critical = false - - th = Thread.start { - Thread.critical = true - begin - _pid = nil - command.notify("job(%id) start to waiting finish.", @shell.debug?) - Thread.critical = false - _pid = Process.waitpid(pid, nil) - rescue Errno::ECHILD - command.notify "warn: job(%id) was done already waitipd." - _pid = true - ensure - # when the process ends, wait until the command termintes - if _pid - else - command.notify("notice: Process finishing...", - "wait for Job[%id] to finish.", - "You can use Shell#transact or Shell#check_point for more safe execution.") - redo - end - Thread.exclusive do - @job_monitor.synchronize do - terminate_job(command) - @job_condition.signal - command.notify "job(%id) finish.", @shell.debug? - end - end - end - } + + pid_mutex.synchronize do + while !pid + pid_cv.wait(pid_mutex) + end + end + return pid, pipe_me_in, pipe_me_out end end diff --git a/lib/shell/system-command.rb b/lib/shell/system-command.rb index 8b1cba98c8..af22ed90d7 100644 --- a/lib/shell/system-command.rb +++ b/lib/shell/system-command.rb @@ -1,13 +1,13 @@ +# frozen_string_literal: false # -# shell/system-command.rb - -# $Release Version: 0.6.0 $ -# $Revision: 1.2.2.1 $ -# $Date: 2004/03/21 12:21:11 $ -# by Keiju ISHITSUKA(Nihon Rational Software Co.,Ltd) +# shell/system-command.rb - +# $Release Version: 0.7 $ +# $Revision$ +# by Keiju ISHITSUKA(keiju@ruby-lang.org) # # -- # -# +# # require "shell/filter" @@ -16,13 +16,13 @@ class Shell class SystemCommand < Filter def initialize(sh, command, *opts) if t = opts.find{|opt| !opt.kind_of?(String) && opt.class} - Shell.Fail Error::TypeError, t.class, "String" + Shell.Fail TypeError, t.class, "String" end super(sh) @command = command @opts = opts - - @input_queue = Queue.new + + @input_queue = Thread::Queue.new @pid = nil sh.process_controller.add_schedule(self) @@ -42,17 +42,20 @@ class Shell def input=(inp) super if active? - start_export + start_export end end def start + notify([@command, *@opts].join(" ")) + @pid, @pipe_in, @pipe_out = @shell.process_controller.sfork(self) { - Dir.chdir @shell.pwd - exec(@command, *@opts) + Dir.chdir @shell.pwd + $0 = @command + exec(@command, *@opts) } if @input - start_export + start_export end start_import end @@ -63,105 +66,93 @@ class Shell def terminate begin - @pipe_in.close + @pipe_in.close rescue IOError end begin - @pipe_out.close + @pipe_out.close rescue IOError end end def kill(sig) if @pid - Process.kill(sig, @pid) + Process.kill(sig, @pid) end end - def start_import -# Thread.critical = true notify "Job(%id) start imp-pipe.", @shell.debug? - rs = @shell.record_separator unless rs _eop = true -# Thread.critical = false - th = Thread.start { - Thread.critical = true - begin - Thread.critical = false - while l = @pipe_in.gets - @input_queue.push l - end - _eop = false - rescue Errno::EPIPE - _eop = false - ensure - if _eop - notify("warn: Process finishing...", - "wait for Job[%id] to finish pipe importing.", - "You can use Shell#transact or Shell#check_point for more safe execution.") -# Tracer.on - Thread.current.run - redo - end - Thread.exclusive do - notify "job(%id}) close imp-pipe.", @shell.debug? - @input_queue.push :EOF - @pipe_in.close - end - end + Thread.start { + begin + while l = @pipe_in.gets + @input_queue.push l + end + _eop = false + rescue Errno::EPIPE + _eop = false + ensure + if !ProcessController::USING_AT_EXIT_WHEN_PROCESS_EXIT and _eop + notify("warn: Process finishing...", + "wait for Job[%id] to finish pipe importing.", + "You can use Shell#transact or Shell#check_point for more safe execution.") + redo + end + notify "job(%id}) close imp-pipe.", @shell.debug? + @input_queue.push :EOF + @pipe_in.close + end } end def start_export notify "job(%id) start exp-pipe.", @shell.debug? _eop = true - th = Thread.start{ - Thread.critical = true - begin - Thread.critical = false - @input.each{|l| @pipe_out.print l} - _eop = false - rescue Errno::EPIPE - _eop = false - ensure - if _eop - notify("shell: warn: Process finishing...", - "wait for Job(%id) to finish pipe exporting.", - "You can use Shell#transact or Shell#check_point for more safe execution.") -# Tracer.on - redo - end - Thread.exclusive do - notify "job(%id) close exp-pipe.", @shell.debug? - @pipe_out.close - end - end + Thread.start{ + begin + @input.each do |l| + ProcessController::block_output_synchronize do + @pipe_out.print l + end + end + _eop = false + rescue Errno::EPIPE, Errno::EIO + _eop = false + ensure + if !ProcessController::USING_AT_EXIT_WHEN_PROCESS_EXIT and _eop + notify("shell: warn: Process finishing...", + "wait for Job(%id) to finish pipe exporting.", + "You can use Shell#transact or Shell#check_point for more safe execution.") + redo + end + notify "job(%id) close exp-pipe.", @shell.debug? + @pipe_out.close + end } end alias super_each each def each(rs = nil) while (l = @input_queue.pop) != :EOF - yield l + yield l end end # ex) - # if you wish to output: - # "shell: job(#{@command}:#{@pid}) close pipe-out." - # then - # mes: "job(%id) close pipe-out." + # if you wish to output: + # "shell: job(#{@command}:#{@pid}) close pipe-out." + # then + # mes: "job(%id) close pipe-out." # yorn: Boolean(@shell.debug? or @shell.verbose?) - def notify(*opts, &block) - Thread.exclusive do - @shell.notify(*opts) {|mes| - yield mes if iterator? - - mes.gsub!("%id", "#{@command}:##{@pid}") - mes.gsub!("%name", "#{@command}") - mes.gsub!("%pid", "#{@pid}") - } + def notify(*opts) + @shell.notify(*opts) do |mes| + yield mes if iterator? + + mes.gsub!("%id", "#{@command}:##{@pid}") + mes.gsub!("%name", "#{@command}") + mes.gsub!("%pid", "#{@pid}") + mes end end end diff --git a/lib/shell/version.rb b/lib/shell/version.rb index 46b3425afa..bb4e7dfb8e 100644 --- a/lib/shell/version.rb +++ b/lib/shell/version.rb @@ -1,16 +1,16 @@ +# frozen_string_literal: false # # version.rb - shell version definition file -# $Release Version: 0.6.0$ -# $Revision: 1.1 $ -# $Date: 2001/05/17 10:02:48 $ -# by Keiju ISHITSUKA(Nihon Rational Software Co.,Ltd) +# $Release Version: 0.7$ +# $Revision$ +# by Keiju ISHITSUKA(keiju@ruby-lang.org) # # -- # -# +# # -class Shell - @RELEASE_VERSION = "0.6.0" - @LAST_UPDATE_DATE = "01/03/19" +class Shell # :nodoc: + @RELEASE_VERSION = "0.7" + @LAST_UPDATE_DATE = "07/03/20" end |
