Skip to content
This repository
Newer
Older
100644 300 lines (249 sloc) 5.826 kb
511dc44a » Laurent Sansonetti
2008-02-25 initial import
1 #
2 # shell.rb -
3 # $Release Version: 0.7 $
4 # $Revision: 1.9 $
5 # by Keiju ISHITSUKA(keiju@ruby-lang.org)
6 #
7 # --
8 #
9 #
10 #
11
12 require "e2mmap"
13
14 require "thread" unless defined?(Mutex)
15
16 require "forwardable"
17
18 require "shell/error"
19 require "shell/command-processor"
20 require "shell/process-controller"
21
22 class Shell
23 @RCS_ID='-$Id: shell.rb,v 1.9 2002/03/04 12:01:10 keiju Exp keiju $-'
24
25 include Error
26 extend Exception2MessageMapper
27
28 # @cascade = true
29 # debug: true -> normal debug
30 # debug: 1 -> eval definition debug
31 # debug: 2 -> detail inspect debug
32 @debug = false
33 @verbose = true
34
35 @debug_display_process_id = false
36 @debug_display_thread_id = true
37 @debug_output_mutex = Mutex.new
38
39 class << Shell
40 extend Forwardable
41
42 attr_accessor :cascade, :debug, :verbose
43
44 # alias cascade? cascade
45 alias debug? debug
46 alias verbose? verbose
47 @verbose = true
48
49 def debug=(val)
50 @debug = val
51 @verbose = val if val
52 end
53
54 def cd(path)
55 new(path)
56 end
57
58 def default_system_path
59 if @default_system_path
60 @default_system_path
61 else
62 ENV["PATH"].split(":")
63 end
64 end
65
66 def default_system_path=(path)
67 @default_system_path = path
68 end
69
70 def default_record_separator
71 if @default_record_separator
72 @default_record_separator
73 else
74 $/
75 end
76 end
77
78 def default_record_separator=(rs)
79 @default_record_separator = rs
80 end
81
82 # os resource mutecs
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)
86 end
87
88 end
89
90 def initialize(pwd = Dir.pwd, umask = nil)
91 @cwd = File.expand_path(pwd)
92 @dir_stack = []
93 @umask = umask
94
95 @system_path = Shell.default_system_path
96 @record_separator = Shell.default_record_separator
97
98 @command_processor = CommandProcessor.new(self)
99 @process_controller = ProcessController.new(self)
100
101 @verbose = Shell.verbose
102 @debug = Shell.debug
103 end
104
105 attr_reader :system_path
106
107 def system_path=(path)
108 @system_path = path
109 rehash
110 end
111
112 attr_accessor :umask, :record_separator
113 attr_accessor :verbose, :debug
114
115 def debug=(val)
116 @debug = val
117 @verbose = val if val
118 end
119
120 alias verbose? verbose
121 alias debug? debug
122
123 attr_reader :command_processor
124 attr_reader :process_controller
125
126 def expand_path(path)
127 File.expand_path(path, @cwd)
128 end
129
130 # Most Shell commands are defined via CommandProcessor
131
132 #
133 # Dir related methods
134 #
135 # Shell#cwd/dir/getwd/pwd
136 # Shell#chdir/cd
137 # Shell#pushdir/pushd
138 # Shell#popdir/popd
139 # Shell#mkdir
140 # Shell#rmdir
141
142 attr_reader :cwd
143 alias dir cwd
144 alias getwd cwd
145 alias pwd cwd
146
147 attr_reader :dir_stack
148 alias dirs dir_stack
149
150 # If called as iterator, it restores the current directory when the
151 # block ends.
152 def chdir(path = nil, verbose = @verbose)
153 check_point
154
155 if iterator?
156 notify("chdir(with block) #{path}") if verbose
157 cwd_old = @cwd
158 begin
159 chdir(path, nil)
160 yield
161 ensure
162 chdir(cwd_old, nil)
163 end
164 else
165 notify("chdir #{path}") if verbose
166 path = "~" unless path
167 @cwd = expand_path(path)
168 notify "current dir: #{@cwd}"
169 rehash
170 Void.new(self)
171 end
172 end
173 alias cd chdir
174
175 def pushdir(path = nil, verbose = @verbose)
176 check_point
177
178 if iterator?
179 notify("pushdir(with block) #{path}") if verbose
180 pushdir(path, nil)
181 begin
182 yield
183 ensure
184 popdir
185 end
186 elsif path
187 notify("pushdir #{path}") if verbose
188 @dir_stack.push @cwd
189 chdir(path, nil)
190 notify "dir stack: [#{@dir_stack.join ', '}]"
191 self
192 else
193 notify("pushdir") if verbose
194 if pop = @dir_stack.pop
195 @dir_stack.push @cwd
196 chdir pop
197 notify "dir stack: [#{@dir_stack.join ', '}]"
198 self
199 else
200 Shell.Fail DirStackEmpty
201 end
202 end
203 Void.new(self)
204 end
205 alias pushd pushdir
206
207 def popdir
208 check_point
209
210 notify("popdir")
211 if pop = @dir_stack.pop
212 chdir pop
213 notify "dir stack: [#{@dir_stack.join ', '}]"
214 self
215 else
216 Shell.Fail DirStackEmpty
217 end
218 Void.new(self)
219 end
220 alias popd popdir
221
222 #
223 # process management
224 #
225 def jobs
226 @process_controller.jobs
227 end
228
229 def kill(sig, command)
230 @process_controller.kill_job(sig, command)
231 end
232
233 #
234 # command definitions
235 #
236 def Shell.def_system_command(command, path = command)
237 CommandProcessor.def_system_command(command, path)
238 end
239
240 def Shell.undef_system_command(command)
241 CommandProcessor.undef_system_command(command)
242 end
243
244 def Shell.alias_command(ali, command, *opts, &block)
245 CommandProcessor.alias_command(ali, command, *opts, &block)
246 end
247
248 def Shell.unalias_command(ali)
249 CommandProcessor.unalias_command(ali)
250 end
251
252 def Shell.install_system_commands(pre = "sys_")
253 CommandProcessor.install_system_commands(pre)
254 end
255
256 #
257 def inspect
258 if debug.kind_of?(Integer) && debug > 2
259 super
260 else
261 to_s
262 end
263 end
264
265 def self.notify(*opts, &block)
266 Shell::debug_output_synchronize do
267 if opts[-1].kind_of?(String)
268 yorn = verbose?
269 else
270 yorn = opts.pop
271 end
272 return unless yorn
273
274 if @debug_display_thread_id
275 if @debug_display_process_id
276 prefix = "shell(##{Process.pid}:#{Thread.current.to_s.sub("Thread", "Th")}): "
277 else
278 prefix = "shell(#{Thread.current.to_s.sub("Thread", "Th")}): "
279 end
280 else
281 prefix = "shell: "
282 end
283 _head = true
284 STDERR.print opts.collect{|mes|
285 mes = mes.dup
286 yield mes if iterator?
287 if _head
288 _head = false
289 # "shell" " + mes
290 prefix + mes
291 else
292 " "* prefix.size + mes
293 end
294 }.join("\n")+"\n"
295 end
296 end
297
298 CommandProcessor.initialize
299 CommandProcessor.run_config
300 end
Something went wrong with that request. Please try again.