From b29c2aca6cc2242e6c750a2d1bcf23f0a8793013 Mon Sep 17 00:00:00 2001 From: Daniel Liu Date: Tue, 30 May 2023 17:48:26 +0900 Subject: [PATCH] 'Jobs builtin using JobManager' --- shrs/src/shell.rs | 21 ++++--- shrs_core/src/builtin/jobs.rs | 6 +- shrs_core/src/hooks.rs | 6 +- shrs_core/src/jobs.rs | 100 ---------------------------------- shrs_core/src/lib.rs | 5 +- shrs_core/src/shell.rs | 2 - shrs_lang/src/eval2.rs | 20 ++++--- shrs_lang/src/lang.rs | 3 +- 8 files changed, 33 insertions(+), 130 deletions(-) delete mode 100644 shrs_core/src/jobs.rs diff --git a/shrs/src/shell.rs b/shrs/src/shell.rs index e2e97fac..cb92252b 100644 --- a/shrs/src/shell.rs +++ b/shrs/src/shell.rs @@ -13,7 +13,7 @@ use shrs_core::{ builtin::Builtins, dummy_child, hooks::{BeforeCommandCtx, Hooks, JobExitCtx, StartupCtx}, - Alias, Context, Env, ExitStatus, Jobs, Lang, Runtime, Shell, Signals, State, Theme, + Alias, Context, Env, Lang, Runtime, Shell, Signals, State, Theme, }; use shrs_job::JobManager; use shrs_lang::PosixLang; @@ -101,7 +101,6 @@ impl ShellConfig { alias: self.alias, out: BufWriter::new(stdout()), state: self.state, - jobs: Jobs::new(), startup_time: Instant::now(), }; let mut rt = Runtime { @@ -178,14 +177,14 @@ fn run_shell( } // check up on running jobs - let mut exit_statuses = vec![]; - ctx.jobs.retain(|status: ExitStatus| { - exit_statuses.push(status); - }); - - for status in exit_statuses.into_iter() { - sh.hooks - .run::(sh, ctx, rt, JobExitCtx { status }); - } + // let mut exit_statuses = vec![]; + // ctx.jobs.retain(|status: ExitStatus| { + // exit_statuses.push(status); + // }); + + // for status in exit_statuses.into_iter() { + // sh.hooks + // .run::(sh, ctx, rt, JobExitCtx { status }); + // } } } diff --git a/shrs_core/src/builtin/jobs.rs b/shrs_core/src/builtin/jobs.rs index 3582015b..26a57600 100644 --- a/shrs_core/src/builtin/jobs.rs +++ b/shrs_core/src/builtin/jobs.rs @@ -1,4 +1,5 @@ use std::{ + borrow::Borrow, env, path::{Path, PathBuf}, }; @@ -21,8 +22,9 @@ impl BuiltinCmd for JobsBuiltin { rt: &mut Runtime, args: &Vec, ) -> anyhow::Result { - for (job_id, _) in ctx.jobs.iter() { - println!("{}", job_id); + let job_manager = sh.job_manager.borrow(); + for job in job_manager.get_jobs() { + println!("{} {}", job.id(), job.display()); } Ok(BuiltinStatus::success()) diff --git a/shrs_core/src/hooks.rs b/shrs_core/src/hooks.rs index 1ebd5f15..71b073a9 100644 --- a/shrs_core/src/hooks.rs +++ b/shrs_core/src/hooks.rs @@ -21,7 +21,7 @@ use std::{ use crossterm::{style::Print, QueueableCommand}; -use crate::{jobs::ExitStatus, Context, Runtime, Shell}; +use crate::{Context, Runtime, Shell}; pub type HookFn = fn(sh: &Shell, sh_ctx: &mut Context, sh_rt: &mut Runtime, ctx: &C) -> anyhow::Result<()>; @@ -111,7 +111,7 @@ pub fn change_dir_hook( /// Context for [JobExit] #[derive(Clone)] pub struct JobExitCtx { - pub status: ExitStatus, + // pub status: ExitStatus, } /// Default [JobExitHook] @@ -121,7 +121,7 @@ pub fn job_exit_hook( sh_rt: &mut Runtime, ctx: &JobExitCtx, ) -> anyhow::Result<()> { - println!("[exit +{}]", ctx.status.code()); + // println!("[exit +{}]", ctx.status.code()); Ok(()) } diff --git a/shrs_core/src/jobs.rs b/shrs_core/src/jobs.rs deleted file mode 100644 index 8c7e015f..00000000 --- a/shrs_core/src/jobs.rs +++ /dev/null @@ -1,100 +0,0 @@ -//! Abstraction layer for processes -use std::{ - collections::{hash_map::Iter, HashMap}, - process::Child, -}; - -use anyhow::anyhow; -use pino_deref::Deref; - -pub type JobId = u32; - -#[derive(Deref, Clone)] -pub struct ExitStatus(pub i32); - -impl ExitStatus { - pub fn success(&self) -> bool { - self.0 == 0 - } - pub fn code(&self) -> i32 { - self.0 - } -} - -pub struct JobInfo { - pub child: Child, - pub cmd: String, -} - -/// Keeps track of all the current running jobs -pub struct Jobs { - foreground: Option, - next_id: JobId, - jobs: HashMap, -} - -impl Jobs { - pub fn new() -> Self { - Jobs { - next_id: 0, - jobs: HashMap::new(), - foreground: None, - } - } - - /// Add new job to be tracked - pub fn push(&mut self, child: Child, cmd: String) { - let next_id = self.get_next_id(); - self.jobs.insert(next_id, JobInfo { child, cmd }); - } - - pub fn iter(&self) -> Iter<'_, JobId, JobInfo> { - self.jobs.iter() - } - - /// Clean up finished jobs - pub fn retain(&mut self, mut exit_handler: F) - where - F: FnMut(ExitStatus), - { - self.jobs.retain(|k, v| { - match v.child.try_wait() { - Ok(Some(status)) => { - exit_handler(ExitStatus(status.code().unwrap())); - false - }, - Ok(None) => true, - Err(e) => { - // TODO should throw error that there was issue waiting for job to finish - false - }, - } - }); - } - - /// Increment internally used id and get the next avaliable one - /// - /// Careful of overflow! - fn get_next_id(&mut self) -> JobId { - self.next_id += 1; - self.next_id - } - - /// Set the current foreground process - pub fn set_foreground(&mut self, child: Child) -> anyhow::Result<()> { - if self.foreground.is_some() { - // TODO move the current foreground to a background task? - return Err(anyhow!("There is already a foreground process")); - } - self.foreground = Some(child); - Ok(()) - } - - /// Wait for foreground to terminate - pub fn wait_foreground(&mut self) -> anyhow::Result { - match self.foreground.take() { - Some(mut fg) => fg.wait().map_err(|e| anyhow!("{e:?}")), - None => Err(anyhow!("No running foreground process")), - } - } -} diff --git a/shrs_core/src/lib.rs b/shrs_core/src/lib.rs index 2e6c89f5..af3d583b 100644 --- a/shrs_core/src/lib.rs +++ b/shrs_core/src/lib.rs @@ -35,12 +35,9 @@ mod state; pub use state::State; mod lang; -pub use lang::Lang; - -mod jobs; // TODO temp re-export anyhow pub use anyhow; -pub use jobs::{ExitStatus, JobId, JobInfo, Jobs}; +pub use lang::Lang; /* #[cfg(test)] diff --git a/shrs_core/src/shell.rs b/shrs_core/src/shell.rs index abe5e95e..0f9ec60c 100644 --- a/shrs_core/src/shell.rs +++ b/shrs_core/src/shell.rs @@ -24,7 +24,6 @@ use crate::{ builtin::Builtins, env::Env, hooks::{AfterCommandCtx, BeforeCommandCtx, Hooks, JobExitCtx, StartupCtx}, - jobs::{ExitStatus, Jobs}, signal::Signals, state::State, theme::Theme, @@ -57,7 +56,6 @@ pub struct Context { /// Output stream pub out: BufWriter, pub state: State, - pub jobs: Jobs, pub startup_time: Instant, } diff --git a/shrs_lang/src/eval2.rs b/shrs_lang/src/eval2.rs index 193a27e9..fcb04cb9 100644 --- a/shrs_lang/src/eval2.rs +++ b/shrs_lang/src/eval2.rs @@ -20,6 +20,10 @@ pub fn run_job( pgid: Option, foreground: bool, ) -> anyhow::Result<()> { + if procs.is_empty() { + return Ok(()); + } + let proc_group = ProcessGroup { id: pgid, processes: procs, @@ -41,6 +45,7 @@ pub fn run_job( pub fn eval_command( job_manager: &mut JobManager, cmd: &ast::Command, + pgid: Option, stdin: Option, stdout: Option, ) -> anyhow::Result<(Vec>, Option)> { @@ -63,29 +68,30 @@ pub fn eval_command( proc_stdin, proc_stdout, Output::Inherit, - None, + pgid, )?; Ok((vec![proc], pgid)) }, ast::Command::Pipeline(a_cmd, b_cmd) => { - let (mut a_procs, a_pgid) = - eval_command(job_manager, a_cmd, stdin, Some(Output::CreatePipe))?; - let (b_procs, b_pgid) = eval_command( + let (mut a_procs, pgid) = + eval_command(job_manager, a_cmd, pgid, stdin, Some(Output::CreatePipe))?; + let (b_procs, pgid) = eval_command( job_manager, b_cmd, + pgid, a_procs.last_mut().unwrap().stdout(), stdout, )?; a_procs.extend(b_procs); - Ok((a_procs, b_pgid)) + Ok((a_procs, pgid)) }, ast::Command::AsyncList(a_cmd, b_cmd) => { // TODO double check stdin and stdout - let (procs, pgid) = eval_command(job_manager, a_cmd, None, None)?; + let (procs, pgid) = eval_command(job_manager, a_cmd, pgid, None, None)?; run_job(job_manager, procs, pgid, false)?; if let Some(b_cmd) = b_cmd { - eval_command(job_manager, b_cmd, None, None) + eval_command(job_manager, b_cmd, pgid, None, None) } else { Ok((vec![], None)) } diff --git a/shrs_lang/src/lang.rs b/shrs_lang/src/lang.rs index 3d0db5e0..5b44acd9 100644 --- a/shrs_lang/src/lang.rs +++ b/shrs_lang/src/lang.rs @@ -57,7 +57,8 @@ impl Lang for PosixLang { println!("{:?}", cmd); let mut job_manager = sh.job_manager.borrow_mut(); - let (procs, pgid) = eval2::eval_command(&mut job_manager, &cmd, None, None)?; + job_manager.do_job_notification(); + let (procs, pgid) = eval2::eval_command(&mut job_manager, &cmd, None, None, None)?; run_job(&mut job_manager, procs, pgid, true)?;