Skip to content

Commit

Permalink
Merge pull request #58 from nicmr/feature/result-instead-of-exit
Browse files Browse the repository at this point in the history
Replace process:exit in functions with Result + error handling
  • Loading branch information
Ramilito authored Jul 19, 2024
2 parents d1ccfb3 + 6e0af3e commit 1a0ccc0
Show file tree
Hide file tree
Showing 6 changed files with 140 additions and 114 deletions.
54 changes: 33 additions & 21 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ serde_yaml = "0.9.3"
serde = { version = "1.0.141", features = ["derive"] }
lazy_static = "1.4.0"
skim = "0.9.4"
thiserror = "1.0.56"

[dev-dependencies]
assert_cmd = "2.0"
43 changes: 11 additions & 32 deletions src/commands.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
use crate::model::KubeConfig;
use crate::{error::SetContextError, model::KubeConfig};
use crate::config;

use core::fmt;
use std::process;
use std::{
io::Cursor,
process::{Command, Stdio},
Expand Down Expand Up @@ -66,25 +64,21 @@ pub fn get_current_context() -> String {
String::from_utf8(output.stdout).unwrap().trim().to_owned()
}

pub fn selectable_list(input: Vec<String>) -> String {
/// Prompts the user to select an item from a list.
/// Returns the selected item or `None` if no item was selected
pub fn selectable_list(input: Vec<String>) -> Option<String> {
let input: Vec<String> = input.into_iter().rev().collect();
let options = SkimOptionsBuilder::default().multi(false).build().unwrap();
let item_reader = SkimItemReader::default();

let items = item_reader.of_bufread(Cursor::new(input.join("\n")));
let selected_items = Skim::run_with(&options, Some(items))
.map(|out| match out.final_key {
Key::Enter => out.selected_items,
_ => Vec::new(),
Skim::run_with(&options, Some(items))
.and_then(|out| match out.final_key {
Key::Enter => Some(out.selected_items),
_ => None,
})
.unwrap_or_default();

if selected_items.is_empty() {
eprintln!("No item selected");
process::exit(1);
}

selected_items[0].output().to_string()
.filter(|selected_items| !selected_items.is_empty())
.map(|selected_items| selected_items[0].output().to_string())
}

pub fn set_namespace(ctx: &str, selection: &str, temp_dir: &str, config: &KubeConfig) {
Expand All @@ -97,21 +91,6 @@ pub fn set_context(ctx: &str, temp_dir: &str, config: &KubeConfig) -> Result<(),
config::write(choice, None, temp_dir);
Ok(())
} else {
Err(SetContextError::ContextNotFound{ctx: ctx.to_owned()})
}
}

#[derive(Debug, Clone)]
pub enum SetContextError {
ContextNotFound {
ctx : String
},
}

impl fmt::Display for SetContextError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
SetContextError::ContextNotFound{ctx} => write!(f, "no context exists with the name: \"{}\"", ctx),
}
Err(SetContextError::KubeContextNotFound{ctx: ctx.to_owned()})
}
}
19 changes: 19 additions & 0 deletions src/error.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
use thiserror::Error;

#[derive(Error, Debug)]
pub enum Error {
#[error("failed to set context: {0}")]
SetContext(#[source] SetContextError),
#[error("no item selected when prompted to select {prompt}")]
NoItemSelected {
prompt: &'static str
},
}

#[derive(Error, Debug)]
pub enum SetContextError {
#[error("no context exists with the name {ctx}")]
KubeContextNotFound {
ctx: String
},
}
29 changes: 21 additions & 8 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,13 @@ mod commands;
mod config;
mod model;
mod modes;
mod error;

use crate::error::Error;
use clap::Parser;
use std::env;
use std::io;
use std::process;

#[macro_use]
extern crate lazy_static;
Expand Down Expand Up @@ -68,22 +71,32 @@ enum Mode {
}

impl Mode {
fn invoke(&self) {
fn invoke(&self) -> Result <(), Error> {
let args = Cli::parse();
match self {
Mode::Namespace => modes::namespace(Cli::parse()),
Mode::Context => modes::context(Cli::parse()),
Mode::DefaultContext => modes::default_context(Cli::parse()),
Mode::DefaultNamespace => modes::default_namespace(Cli::parse()),
Mode::CompletionContext => modes::completion_context(Cli::parse()),
Mode::CompletionNamespace => modes::completion_namespace(Cli::parse()),
Mode::Namespace => modes::namespace(args),
Mode::Context => modes::context(args),
Mode::DefaultContext => modes::default_context(args),
Mode::DefaultNamespace => modes::default_namespace(args),
Mode::CompletionContext => {
modes::completion_context(args);
Ok(())
},
Mode::CompletionNamespace => {
modes::completion_namespace(args);
Ok(())
}
}
}
}

fn main() -> Result<(), io::Error> {
let args = Cli::parse();

Mode::invoke(&args.mode);
if let Err(err) = Mode::invoke(&args.mode) {
eprintln!("error: {}", err);
process::exit(1);
}

Ok(())
}
Loading

0 comments on commit 1a0ccc0

Please sign in to comment.