mirror of
https://github.com/samsonjs/csc360-a1-shell.git
synced 2026-03-25 08:45:52 +00:00
Perform proper shell word splitting and improve logging
This commit is contained in:
parent
01b0983f79
commit
9faa33fbf2
3 changed files with 39 additions and 32 deletions
|
|
@ -2,7 +2,7 @@ class Shell
|
|||
class Builtins
|
||||
attr_reader :logger
|
||||
|
||||
def initialize(logger)
|
||||
def initialize(logger = ShellLogger.instance)
|
||||
@logger = logger
|
||||
end
|
||||
|
||||
|
|
|
|||
53
ruby/main.rb
53
ruby/main.rb
|
|
@ -3,6 +3,7 @@
|
|||
require 'English'
|
||||
require 'open3'
|
||||
require 'readline'
|
||||
require 'shellwords'
|
||||
|
||||
require './builtins'
|
||||
require './colours'
|
||||
|
|
@ -12,12 +13,12 @@ require './job'
|
|||
class Shell
|
||||
attr_reader :logger, :options
|
||||
|
||||
def initialize(args)
|
||||
@logger = ShellLogger.new
|
||||
@options = parse_options(args)
|
||||
def initialize(args = ARGV)
|
||||
@builtins = Builtins.new
|
||||
@jobs_by_pid = {}
|
||||
@builtins = Builtins.new(@logger)
|
||||
logger.verbose "options: #{options.inspect}"
|
||||
@logger = ShellLogger.instance
|
||||
@options = parse_options(args)
|
||||
logger.verbose "Options: #{options.inspect}"
|
||||
end
|
||||
|
||||
def main
|
||||
|
|
@ -26,13 +27,13 @@ class Shell
|
|||
if options[:command]
|
||||
logger.verbose "Executing command: #{options[:command]}"
|
||||
print_logs
|
||||
exit exec_command(options[:command])
|
||||
exit process_command(options[:command])
|
||||
elsif $stdin.isatty
|
||||
add_to_history = true
|
||||
loop do
|
||||
print_logs
|
||||
cmd = Readline.readline(prompt(Dir.pwd), add_to_history)
|
||||
process_command(cmd)
|
||||
line = Readline.readline(prompt(Dir.pwd), add_to_history)
|
||||
process_command(line)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -78,39 +79,35 @@ class Shell
|
|||
message = "#{log.message}#{CLEAR}"
|
||||
case log.level
|
||||
when :verbose
|
||||
puts message if options[:verbose]
|
||||
when :warning
|
||||
warn message
|
||||
warn message if options[:verbose]
|
||||
else
|
||||
puts message
|
||||
warn message
|
||||
end
|
||||
end
|
||||
logger.clear
|
||||
end
|
||||
|
||||
def process_command(cmd)
|
||||
logger.verbose "Processing command: #{cmd.inspect}"
|
||||
exit 0 if cmd.nil? # EOF, ctrl-d
|
||||
return if cmd.empty? # no input, no-op
|
||||
def process_command(line)
|
||||
logger.verbose "Processing command: #{line.inspect}"
|
||||
exit 0 if line.nil? # EOF, ctrl-d
|
||||
return if line.empty? # no input, no-op
|
||||
|
||||
# TODO: proper word splitting, pass arrays to built-ins
|
||||
args = cmd.split
|
||||
argv0 = args.first
|
||||
logger.verbose "\"Words\": #{args.inspect}"
|
||||
if @builtins.builtin?(argv0)
|
||||
logger.verbose "Executing builtin #{argv0}"
|
||||
args.shift
|
||||
@builtins.exec(argv0, args)
|
||||
args = Shellwords.split(line)
|
||||
cmd = args.shift
|
||||
logger.verbose "Words: #{cmd} #{args.inspect}"
|
||||
if @builtins.builtin?(cmd)
|
||||
logger.verbose "Executing builtin #{cmd}"
|
||||
@builtins.exec(cmd, args)
|
||||
else
|
||||
logger.verbose "Shelling out for #{argv0}"
|
||||
status = exec_command(cmd)
|
||||
logger.verbose "Shelling out for #{cmd}"
|
||||
status = exec_command(cmd, args)
|
||||
print "#{RED}-#{status}-#{CLEAR} " unless status.zero?
|
||||
end
|
||||
end
|
||||
|
||||
def exec_command(cmd)
|
||||
def exec_command(cmd, args)
|
||||
# TODO: background execution using fork + exec, streaming output
|
||||
out, err, status = Open3.capture3(cmd)
|
||||
out, err, status = Open3.capture3(cmd + ' ' + args.join(' '))
|
||||
puts out.chomp unless out.empty?
|
||||
warn err.chomp unless err.empty?
|
||||
status.exitstatus
|
||||
|
|
|
|||
|
|
@ -1,3 +1,5 @@
|
|||
require './colours'
|
||||
|
||||
# Queues up messages to be printed out when readline is waiting for input, to prevent
|
||||
# mixing shell output with command output.
|
||||
class ShellLogger
|
||||
|
|
@ -5,21 +7,29 @@ class ShellLogger
|
|||
|
||||
attr_reader :logs
|
||||
|
||||
def self.instance
|
||||
@instance ||= new
|
||||
end
|
||||
|
||||
def initialize
|
||||
clear
|
||||
end
|
||||
|
||||
def log(message)
|
||||
@logs << Log.new(:info, message)
|
||||
@logs << Log.new(:info, "#{WHITE}[INFO]#{CLEAR} #{message}")
|
||||
end
|
||||
alias info log
|
||||
|
||||
def warn(message)
|
||||
@logs << Log.new(:warning, message)
|
||||
@logs << Log.new(:warning, "#{YELLOW}[WARN]#{CLEAR} #{message}")
|
||||
end
|
||||
|
||||
def error(message)
|
||||
@logs << Log.new(:error, "#{RED}[ERROR]#{CLEAR} #{message}")
|
||||
end
|
||||
|
||||
def verbose(message)
|
||||
@logs << Log.new(:verbose, message)
|
||||
@logs << Log.new(:verbose, "[VERBOSE] #{message}")
|
||||
end
|
||||
|
||||
def clear
|
||||
|
|
|
|||
Loading…
Reference in a new issue