mirror of
https://github.com/nushell/nushell.git
synced 2025-04-21 19:58:21 +02:00
Begin job tagging implementation
This commit is contained in:
parent
b0f9cda9b5
commit
71600fd2b6
@ -37,7 +37,7 @@ impl Command for JobList {
|
|||||||
let values = jobs
|
let values = jobs
|
||||||
.iter()
|
.iter()
|
||||||
.map(|(id, job)| {
|
.map(|(id, job)| {
|
||||||
let record = record! {
|
let mut record = record! {
|
||||||
"id" => Value::int(id.get() as i64, head),
|
"id" => Value::int(id.get() as i64, head),
|
||||||
"type" => match job {
|
"type" => match job {
|
||||||
Job::Thread(_) => Value::string("thread", head),
|
Job::Thread(_) => Value::string("thread", head),
|
||||||
@ -52,12 +52,16 @@ impl Command for JobList {
|
|||||||
head,
|
head,
|
||||||
),
|
),
|
||||||
|
|
||||||
Job::Frozen(FrozenJob { unfreeze }) => {
|
Job::Frozen(FrozenJob { unfreeze, .. }) => {
|
||||||
Value::list(vec![ Value::int(unfreeze.pid() as i64, head) ], head)
|
Value::list(vec![ Value::int(unfreeze.pid() as i64, head) ], head)
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if let Some(tag) = job.tag() {
|
||||||
|
record.push("tag", Value::string(tag, head));
|
||||||
|
}
|
||||||
|
|
||||||
Value::record(record, head)
|
Value::record(record, head)
|
||||||
})
|
})
|
||||||
.collect::<Vec<Value>>();
|
.collect::<Vec<Value>>();
|
||||||
|
@ -28,6 +28,12 @@ impl Command for JobSpawn {
|
|||||||
Signature::build("job spawn")
|
Signature::build("job spawn")
|
||||||
.category(Category::Experimental)
|
.category(Category::Experimental)
|
||||||
.input_output_types(vec![(Type::Nothing, Type::Int)])
|
.input_output_types(vec![(Type::Nothing, Type::Int)])
|
||||||
|
.named(
|
||||||
|
"tag",
|
||||||
|
SyntaxShape::String,
|
||||||
|
"An optional description tag for this job",
|
||||||
|
Some('t'),
|
||||||
|
)
|
||||||
.required(
|
.required(
|
||||||
"closure",
|
"closure",
|
||||||
SyntaxShape::Closure(Some(vec![SyntaxShape::Any])),
|
SyntaxShape::Closure(Some(vec![SyntaxShape::Any])),
|
||||||
@ -50,6 +56,8 @@ impl Command for JobSpawn {
|
|||||||
|
|
||||||
let closure: Closure = call.req(engine_state, stack, 0)?;
|
let closure: Closure = call.req(engine_state, stack, 0)?;
|
||||||
|
|
||||||
|
let tag: Option<String> = call.get_flag(engine_state, stack, "tag")?;
|
||||||
|
|
||||||
let mut job_state = engine_state.clone();
|
let mut job_state = engine_state.clone();
|
||||||
job_state.is_interactive = false;
|
job_state.is_interactive = false;
|
||||||
|
|
||||||
@ -68,7 +76,7 @@ impl Command for JobSpawn {
|
|||||||
let mut jobs = jobs.lock().expect("jobs lock is poisoned!");
|
let mut jobs = jobs.lock().expect("jobs lock is poisoned!");
|
||||||
|
|
||||||
let id = {
|
let id = {
|
||||||
let thread_job = ThreadJob::new(job_signals);
|
let thread_job = ThreadJob::new(job_signals, tag);
|
||||||
job_state.current_thread_job = Some(thread_job.clone());
|
job_state.current_thread_job = Some(thread_job.clone());
|
||||||
jobs.add_job(Job::Thread(thread_job))
|
jobs.add_job(Job::Thread(thread_job))
|
||||||
};
|
};
|
||||||
|
64
crates/nu-command/src/experimental/job_tag.rs
Normal file
64
crates/nu-command/src/experimental/job_tag.rs
Normal file
@ -0,0 +1,64 @@
|
|||||||
|
use nu_engine::command_prelude::*;
|
||||||
|
use nu_protocol::JobId;
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct JobTag;
|
||||||
|
|
||||||
|
impl Command for JobTag {
|
||||||
|
fn name(&self) -> &str {
|
||||||
|
"job tag"
|
||||||
|
}
|
||||||
|
|
||||||
|
fn description(&self) -> &str {
|
||||||
|
"Add a tag to a background job."
|
||||||
|
}
|
||||||
|
|
||||||
|
fn signature(&self) -> nu_protocol::Signature {
|
||||||
|
Signature::build("job tag")
|
||||||
|
.category(Category::Experimental)
|
||||||
|
.required("id", SyntaxShape::Int, "The id of the job to tag.")
|
||||||
|
.input_output_types(vec![(Type::Nothing, Type::Nothing)])
|
||||||
|
.allow_variants_without_examples(true)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn search_terms(&self) -> Vec<&str> {
|
||||||
|
vec!["describe", "desc"]
|
||||||
|
}
|
||||||
|
|
||||||
|
fn run(
|
||||||
|
&self,
|
||||||
|
engine_state: &EngineState,
|
||||||
|
stack: &mut Stack,
|
||||||
|
call: &Call,
|
||||||
|
_input: PipelineData,
|
||||||
|
) -> Result<PipelineData, ShellError> {
|
||||||
|
let head = call.head;
|
||||||
|
|
||||||
|
let id_arg: Spanned<i64> = call.req(engine_state, stack, 0)?;
|
||||||
|
|
||||||
|
if id_arg.item < 0 {
|
||||||
|
return Err(ShellError::NeedsPositiveValue { span: id_arg.span });
|
||||||
|
}
|
||||||
|
|
||||||
|
let id: JobId = JobId::new(id_arg.item as usize);
|
||||||
|
|
||||||
|
let mut jobs = engine_state.jobs.lock().expect("jobs lock is poisoned!");
|
||||||
|
|
||||||
|
if jobs.lookup(id).is_none() {
|
||||||
|
return Err(ShellError::JobNotFound {
|
||||||
|
id: id.get(),
|
||||||
|
span: head,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(Value::nothing(head).into_pipeline_data())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn examples(&self) -> Vec<Example> {
|
||||||
|
vec![Example {
|
||||||
|
example: "let id = job spawn { sleep 10sec }; job tag $id",
|
||||||
|
description: "tag a newly spawned job",
|
||||||
|
result: None,
|
||||||
|
}]
|
||||||
|
}
|
||||||
|
}
|
@ -112,7 +112,10 @@ fn unfreeze_job(
|
|||||||
span,
|
span,
|
||||||
}),
|
}),
|
||||||
|
|
||||||
Job::Frozen(FrozenJob { unfreeze: handle }) => {
|
Job::Frozen(FrozenJob {
|
||||||
|
unfreeze: handle,
|
||||||
|
tag,
|
||||||
|
}) => {
|
||||||
let pid = handle.pid();
|
let pid = handle.pid();
|
||||||
|
|
||||||
if let Some(thread_job) = &state.current_thread_job {
|
if let Some(thread_job) = &state.current_thread_job {
|
||||||
@ -141,7 +144,13 @@ fn unfreeze_job(
|
|||||||
Ok(ForegroundWaitStatus::Frozen(handle)) => {
|
Ok(ForegroundWaitStatus::Frozen(handle)) => {
|
||||||
let mut jobs = state.jobs.lock().expect("jobs lock is poisoned!");
|
let mut jobs = state.jobs.lock().expect("jobs lock is poisoned!");
|
||||||
|
|
||||||
jobs.add_job_with_id(old_id, Job::Frozen(FrozenJob { unfreeze: handle }))
|
jobs.add_job_with_id(
|
||||||
|
old_id,
|
||||||
|
Job::Frozen(FrozenJob {
|
||||||
|
unfreeze: handle,
|
||||||
|
tag,
|
||||||
|
}),
|
||||||
|
)
|
||||||
.expect("job was supposed to be removed");
|
.expect("job was supposed to be removed");
|
||||||
|
|
||||||
if state.is_interactive {
|
if state.is_interactive {
|
||||||
|
@ -3,6 +3,7 @@ mod job;
|
|||||||
mod job_kill;
|
mod job_kill;
|
||||||
mod job_list;
|
mod job_list;
|
||||||
mod job_spawn;
|
mod job_spawn;
|
||||||
|
mod job_tag;
|
||||||
|
|
||||||
#[cfg(all(unix, feature = "os"))]
|
#[cfg(all(unix, feature = "os"))]
|
||||||
mod job_unfreeze;
|
mod job_unfreeze;
|
||||||
|
@ -332,7 +332,12 @@ impl Command for External {
|
|||||||
if let ForegroundWaitStatus::Frozen(unfreeze) = status {
|
if let ForegroundWaitStatus::Frozen(unfreeze) = status {
|
||||||
let mut jobs = jobs.lock().expect("jobs lock is poisoned!");
|
let mut jobs = jobs.lock().expect("jobs lock is poisoned!");
|
||||||
|
|
||||||
let job_id = jobs.add_job(Job::Frozen(FrozenJob { unfreeze }));
|
// TODO: use name of process as a tag
|
||||||
|
let job_id = jobs.add_job(Job::Frozen(FrozenJob {
|
||||||
|
unfreeze,
|
||||||
|
tag: None,
|
||||||
|
}));
|
||||||
|
|
||||||
if is_interactive {
|
if is_interactive {
|
||||||
println!("\nJob {} is frozen", job_id.get());
|
println!("\nJob {} is frozen", job_id.get());
|
||||||
}
|
}
|
||||||
|
@ -38,6 +38,10 @@ impl Jobs {
|
|||||||
self.jobs.get(&id)
|
self.jobs.get(&id)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn lookup_mut(&mut self, id: JobId) -> Option<&mut Job> {
|
||||||
|
self.jobs.get_mut(&id)
|
||||||
|
}
|
||||||
|
|
||||||
pub fn remove_job(&mut self, id: JobId) -> Option<Job> {
|
pub fn remove_job(&mut self, id: JobId) -> Option<Job> {
|
||||||
if self.last_frozen_job_id.is_some_and(|last| id == last) {
|
if self.last_frozen_job_id.is_some_and(|last| id == last) {
|
||||||
self.last_frozen_job_id = None;
|
self.last_frozen_job_id = None;
|
||||||
@ -134,13 +138,15 @@ pub enum Job {
|
|||||||
pub struct ThreadJob {
|
pub struct ThreadJob {
|
||||||
signals: Signals,
|
signals: Signals,
|
||||||
pids: Arc<Mutex<HashSet<u32>>>,
|
pids: Arc<Mutex<HashSet<u32>>>,
|
||||||
|
tag: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ThreadJob {
|
impl ThreadJob {
|
||||||
pub fn new(signals: Signals) -> Self {
|
pub fn new(signals: Signals, tag: Option<String>) -> Self {
|
||||||
ThreadJob {
|
ThreadJob {
|
||||||
signals,
|
signals,
|
||||||
pids: Arc::new(Mutex::new(HashSet::default())),
|
pids: Arc::new(Mutex::new(HashSet::default())),
|
||||||
|
tag,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -197,10 +203,18 @@ impl Job {
|
|||||||
Job::Frozen(frozen_job) => frozen_job.kill(),
|
Job::Frozen(frozen_job) => frozen_job.kill(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn tag(&self) -> Option<&String> {
|
||||||
|
match self {
|
||||||
|
Job::Thread(thread_job) => thread_job.tag.as_ref(),
|
||||||
|
Job::Frozen(frozen_job) => frozen_job.tag.as_ref(),
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct FrozenJob {
|
pub struct FrozenJob {
|
||||||
pub unfreeze: UnfreezeHandle,
|
pub unfreeze: UnfreezeHandle,
|
||||||
|
pub tag: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FrozenJob {
|
impl FrozenJob {
|
||||||
|
Loading…
Reference in New Issue
Block a user