Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 15 additions & 4 deletions src/cli/cmd/job/start.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
use crate::{
cli::{cmd::job::logs, complete::complete_job_launcher_id},
data::{simple_message::SimpleMessage, submission_id::SubmissionId},
data::{
launcher_id::{LauncherIdError, LauncherIdOrName},
simple_message::SimpleMessage,
submission_id::SubmissionId,
},
httpclient::{self, data::SessionStartRequest},
};

Expand All @@ -9,7 +13,6 @@ use crate::cli::sink::Error as SinkError;

use clap::{Parser, ValueHint};
use clap_complete::ArgValueCompleter;
use ulid::Ulid;

use snafu::{ResultExt, Snafu};

Expand All @@ -20,7 +23,7 @@ use snafu::{ResultExt, Snafu};
pub struct Input {
/// The launcher to use for launching the job.
#[arg(long, value_hint=ValueHint::Other, add = ArgValueCompleter::new(complete_job_launcher_id))]
pub launcher: Ulid,
pub launcher: LauncherIdOrName,

/// A submission id allows to deduplicate same job submissions. If
/// missing, a random one is generated. It must be at least 4
Expand Down Expand Up @@ -49,6 +52,9 @@ pub enum Error {

#[snafu(display("Http error: {}", source))]
HttpClient { source: httpclient::Error },

#[snafu(display("Launcher id error: {}", source))]
LauncherId { source: LauncherIdError },
}

impl Input {
Expand All @@ -67,8 +73,13 @@ impl Input {
} else {
Some(self.passthrough.clone())
};
let launcher_id = self
.launcher
.resolve(&ctx.client)
.await
.context(LauncherIdSnafu)?;
let req = SessionStartRequest {
launcher_id: self.launcher.to_string(),
launcher_id: launcher_id.to_string(),
session_type: "non-interactive".into(),
submission_id: Some(submission_id),
job_args_override: args,
Expand Down
2 changes: 1 addition & 1 deletion src/cli/cmd/job/stop.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ use snafu::{ResultExt, Snafu};
/// Stop a running non-interactive session.
#[derive(Parser, Debug)]
pub struct Input {
/// The launcher to use for launching the job.
/// The id of the job to stop
#[arg(value_hint=ValueHint::Other, add = ArgValueCompleter::new(complete_job_name))]
pub job_id: String,
}
Expand Down
24 changes: 13 additions & 11 deletions src/cli/complete.rs
Original file line number Diff line number Diff line change
Expand Up @@ -62,20 +62,22 @@ fn parse_common_opts() -> Result<CommonOpts, ClapError> {
async fn make_launcher_completion_candidate(
client: &Client,
launcher: &SessionLauncher,
) -> CompletionCandidate {
) -> Vec<CompletionCandidate> {
let mut help = StyledStr::new();
help.push_str(&launcher.name);
let cc = CompletionCandidate::new(launcher.id.clone());

let Ok(Some(project)) = client.get_project_by_id(&launcher.project_id).await else {
let cc = vec![
CompletionCandidate::new(launcher.id.clone()),
CompletionCandidate::new(launcher.name.clone()),
];

if let Ok(Some(project)) = client.get_project_by_id(&launcher.project_id).await {
help.push_str(" - ");
help.push_str(&project.name);
} else {
eprintln!("Cannot get project details for: {}", launcher.project_id);
return cc.help(Some(help));
};

help.push_str(" - ");
help.push_str(&project.name);
}

cc.help(Some(help))
cc.into_iter().map(|c| c.help(Some(help.clone()))).collect()
}

async fn make_job_name_completion_candidate(
Expand Down Expand Up @@ -149,7 +151,7 @@ pub fn complete_job_launcher_id(current: &ffi::OsStr) -> Vec<CompletionCandidate
})
{
let cc = make_launcher_completion_candidate(&client, launcher).await;
result.push(cc);
result.extend(cc);
}
if result.is_empty() {
eprintln!("No job launchers found.");
Expand Down
1 change: 1 addition & 0 deletions src/data.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ Data types used across the cli

*/

pub mod launcher_id;
pub mod project_id;
pub mod renku_url;
pub mod simple_message;
Expand Down
91 changes: 91 additions & 0 deletions src/data/launcher_id.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
use std::fmt::{self, Display};
use std::str::FromStr;

use crate::httpclient::{Client, Error};
use ulid::Ulid;

#[derive(Debug, Clone, PartialEq)]
pub enum LauncherIdOrName {
Id(Ulid),
Name(String),
}

#[derive(Debug)]
pub enum LauncherIdError {
InvalidInput(String),
RequestError(Error),
NotFound(String),
}

impl LauncherIdOrName {
pub fn parse(s: &str) -> Result<LauncherIdOrName, LauncherIdError> {
s.parse::<LauncherIdOrName>()
}
pub async fn resolve(&self, client: &Client) -> Result<Ulid, LauncherIdError> {
match self {
LauncherIdOrName::Id(ulid) => Ok(*ulid),
LauncherIdOrName::Name(name) => {
let launchers = client
.list_launchers()
.await
.map_err(LauncherIdError::RequestError)?;
match launchers.iter().find(|l| l.name == *name) {
Some(l) => {
l.id.parse::<Ulid>()
.map_err(|_| LauncherIdError::InvalidInput(l.id.clone()))
}
None => Err(LauncherIdError::NotFound(name.clone())),
}
}
}
}
}

impl FromStr for LauncherIdOrName {
type Err = LauncherIdError;

fn from_str(s: &str) -> Result<Self, Self::Err> {
Ok(s.parse::<Ulid>()
.map(LauncherIdOrName::Id)
.unwrap_or_else(|_| LauncherIdOrName::Name(s.to_string())))
}
}

impl fmt::Display for LauncherIdOrName {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(
f,
"{}",
match self {
LauncherIdOrName::Name(name) => {
name.to_string()
}
LauncherIdOrName::Id(id) => id.to_string(),
}
)
}
}
impl Display for LauncherIdError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
LauncherIdError::InvalidInput(msg) => write!(f, "Invalid launcher id: {}", msg),
LauncherIdError::NotFound(name) => write!(f, "Launcher not found: {}", name),
LauncherIdError::RequestError(error) => {
write!(f, "Couldn't resolve launcher name: {}", error)
}
}
}
}
impl std::error::Error for LauncherIdError {}

#[test]
fn read_to_string() {
let id1 = LauncherIdOrName::Name("my-launcher".to_string());
let id2 = LauncherIdOrName::Id(Ulid::generate());

for id in [id1, id2] {
let id_str = format!("{}", id);
let id_parsed = LauncherIdOrName::parse(&id_str).unwrap();
assert_eq!(id, id_parsed);
}
}
Loading