3 # $Release Version: 0.7 $
5 # by Keiju ISHITSUKA(keiju@ruby-lang.org)
14 require "thread" unless defined?(Mutex)
19 require "shell/command-processor"
20 require "shell/process-controller"
23 @RCS_ID='-$Id: shell.rb,v 1.9 2002/03/04 12:01:10 keiju Exp keiju $-'
26 extend Exception2MessageMapper
29 # debug: true -> normal debug
30 # debug: 1 -> eval definition debug
31 # debug: 2 -> detail inspect debug
35 @debug_display_process_id = false
36 @debug_display_thread_id = true
37 @debug_output_mutex = Mutex.new
42 attr_accessor :cascade, :debug, :verbose
44 # alias cascade? cascade
46 alias verbose? verbose
58 def default_system_path
59 if @default_system_path
62 ENV["PATH"].split(":")
66 def default_system_path=(path)
67 @default_system_path = path
70 def default_record_separator
71 if @default_record_separator
72 @default_record_separator
78 def default_record_separator=(rs)
79 @default_record_separator = rs
83 mutex_methods = ["unlock", "lock", "locked?", "synchronize", "try_lock", "exclusive_unlock"]
84 for m in mutex_methods
85 def_delegator("@debug_output_mutex", m, "debug_output_"+m.to_s)
90 def initialize(pwd = Dir.pwd, umask = nil)
91 @cwd = File.expand_path(pwd)
95 @system_path = Shell.default_system_path
96 @record_separator = Shell.default_record_separator
98 @command_processor = CommandProcessor.new(self)
99 @process_controller = ProcessController.new(self)
101 @verbose = Shell.verbose
105 attr_reader :system_path
107 def system_path=(path)
112 attr_accessor :umask, :record_separator
113 attr_accessor :verbose, :debug
117 @verbose = val if val
120 alias verbose? verbose
123 attr_reader :command_processor
124 attr_reader :process_controller
126 def expand_path(path)
127 File.expand_path(path, @cwd)
130 # Most Shell commands are defined via CommandProcessor
133 # Dir related methods
135 # Shell#cwd/dir/getwd/pwd
137 # Shell#pushdir/pushd
147 attr_reader :dir_stack
150 # If called as iterator, it restores the current directory when the
152 def chdir(path = nil, verbose = @verbose)
156 notify("chdir(with block) #{path}") if verbose
165 notify("chdir #{path}") if verbose
166 path = "~" unless path
167 @cwd = expand_path(path)
168 notify "current dir: #{@cwd}"
175 def pushdir(path = nil, verbose = @verbose)
179 notify("pushdir(with block) #{path}") if verbose
187 notify("pushdir #{path}") if verbose
190 notify "dir stack: [#{@dir_stack.join ', '}]"
193 notify("pushdir") if verbose
194 if pop = @dir_stack.pop
197 notify "dir stack: [#{@dir_stack.join ', '}]"
200 Shell.Fail DirStackEmpty
211 if pop = @dir_stack.pop
213 notify "dir stack: [#{@dir_stack.join ', '}]"
216 Shell.Fail DirStackEmpty
226 @process_controller.jobs
229 def kill(sig, command)
230 @process_controller.kill_job(sig, command)
234 # command definitions
236 def Shell.def_system_command(command, path = command)
237 CommandProcessor.def_system_command(command, path)
240 def Shell.undef_system_command(command)
241 CommandProcessor.undef_system_command(command)
244 def Shell.alias_command(ali, command, *opts, &block)
245 CommandProcessor.alias_command(ali, command, *opts, &block)
248 def Shell.unalias_command(ali)
249 CommandProcessor.unalias_command(ali)
252 def Shell.install_system_commands(pre = "sys_")
253 CommandProcessor.install_system_commands(pre)
258 if debug.kind_of?(Integer) && debug > 2
265 def self.notify(*opts, &block)
266 Shell::debug_output_synchronize do
267 if opts[-1].kind_of?(String)
274 if @debug_display_thread_id
275 if @debug_display_process_id
276 prefix = "shell(##{Process.pid}:#{Thread.current.to_s.sub("Thread", "Th")}): "
278 prefix = "shell(#{Thread.current.to_s.sub("Thread", "Th")}): "
284 STDERR.print opts.collect{|mes|
286 yield mes if iterator?
292 " "* prefix.size + mes
298 CommandProcessor.initialize
299 CommandProcessor.run_config