[ruby] Implement bglist and bgkill

This commit is contained in:
Sami Samhuri 2022-01-21 17:39:52 -08:00
parent e7b73fa309
commit 5bb03eb2a2
No known key found for this signature in database
GPG key ID: 4B4195422742FC16
2 changed files with 62 additions and 18 deletions

View file

@ -28,6 +28,28 @@ module Shell
job_control.exec_command(cmd, args, background: true)
end
def builtin_bglist(_args)
jobs = job_control.list
puts unless jobs.empty?
jobs.each do |job|
puts job_control.format_job(job)
end
plural = jobs.count == 1 ? '' : 's'
puts "#{jobs.count} background job#{plural}"
0
end
def builtin_bgkill(args)
if args.count != 1
logger.warn 'Usage: bgkill <job>'
return -1
end
job_id = args.shift.to_i
job_control.kill(job_id)
0
end
def builtin_cd(args)
Dir.chdir args.first
0

View file

@ -15,24 +15,6 @@ module Shell
@logger = logger || Logger.instance
end
def trap_sigchld
# handler for SIGCHLD when a child's state changes
Signal.trap('CHLD') do |_signo|
pid = Process.waitpid(-1, Process::WNOHANG)
if pid.nil?
# no-op
elsif (job = @jobs_by_pid[pid])
time = Time.now.strftime('%T')
job_text = yellow('job ', job.id, ' exited')
args = job.args.inspect
puts "\n[#{time}] #{job_text} #{white('(pid ', pid, ')')}: #{green(job.cmd)} #{args}"
else
warn "\n#{yellow('[WARN]')} No job found for child with PID #{pid}"
end
Readline.refresh_line
end
end
def exec_command(cmd, args, background: false)
unless (path = resolve_executable(cmd))
warn "#{red('[ERROR]')} command not found: #{cmd}"
@ -61,6 +43,46 @@ module Shell
-5
end
def kill(job_id)
job = @jobs_by_pid.values.detect { |j| j.id == job_id }
if job.nil?
logger.warn "No job found with ID #{job_id}"
return
end
Process.kill('TERM', job.pid)
rescue Errno::ESRCH
logger.warn "No such proccess: #{job.pid}"
end
def list
@jobs_by_pid.values.sort_by(&:id)
end
def format_job(job)
args = job.args.join(' ')
"#{yellow(job.id)}: #{white('(pid ', job.pid, ')')} #{green(job.cmd)} #{args}"
end
def trap_sigchld
# handler for SIGCHLD when a child's state changes
Signal.trap('CHLD') do |_signo|
pid = Process.waitpid(-1, Process::WNOHANG)
if pid.nil?
# no-op
elsif (job = @jobs_by_pid[pid])
@jobs_by_pid.delete(pid)
time = Time.now.strftime('%T')
job_text = yellow('job ', job.id, ' exited')
args = job.args.join(' ')
puts "\n[#{time}] #{job_text} #{white('(pid ', job.pid, ')')}: #{green(job.cmd)} #{args}"
else
warn "\n#{yellow('[WARN]')} No job found for child with PID #{pid}"
end
Readline.refresh_line
end
end
# Return absolute and relative paths directly, or searches PATH for a
# matching executable with the given filename and returns its path.
# Returns nil when no such command was found.