use std::path::PathBuf;
use hen::{
collection,
error::{HenError, HenErrorKind, HenResult},
prompt_generator::{collection_prompt, request_prompt, scan_directory},
request,
};
use crate::cli::RunArgs;
pub(crate) fn load_collection(args: &RunArgs, cwd: PathBuf) -> HenResult<collection::Collection> {
if args.non_interactive {
return load_collection_non_interactive(args, cwd);
}
let collection = match args.path.as_ref() {
Some(path) => {
let path = PathBuf::from(path);
if path.is_dir() {
let hen_files = scan_directory(path.clone()).map_err(|err| {
err.with_detail(format!("While scanning directory {}", path.display()))
})?;
if hen_files.len() == 1 {
collection::Collection::new(hen_files[0].clone())
} else {
collection_prompt(path)
}
} else {
collection::Collection::new(path)
}
}
None => collection_prompt(cwd),
}?;
Ok(collection)
}
fn load_collection_non_interactive(
args: &RunArgs,
cwd: PathBuf,
) -> HenResult<collection::Collection> {
let path = args.path.as_ref().map(PathBuf::from).unwrap_or(cwd);
if path.is_dir() {
let hen_files = scan_directory(path.clone()).map_err(|err| {
err.with_detail(format!("While scanning directory {}", path.display()))
})?;
return match hen_files.len() {
0 => Err(
HenError::new(HenErrorKind::Input, "No .hen files found in directory")
.with_detail(format!("Directory: {}", path.display()))
.with_exit_code(2),
),
1 => collection::Collection::new(hen_files[0].clone()),
_ => Err(HenError::new(
HenErrorKind::Input,
"Directory contains multiple .hen files and cannot be resolved non-interactively",
)
.with_detail(format!("Directory: {}", path.display()))
.with_detail("Provide a specific collection file path instead.")
.with_exit_code(2)),
};
}
collection::Collection::new(path)
}
pub(crate) fn resolve_execution_plan(
collection: &collection::Collection,
planner: &request::RequestPlanner,
args: &RunArgs,
) -> HenResult<(Vec<usize>, Vec<usize>, Option<usize>)> {
if args.non_interactive {
return resolve_execution_plan_non_interactive(collection, planner, args.selector.as_deref());
}
match args.selector.as_deref() {
Some("all") => {
let order = planner.order_all();
Ok((order.clone(), order, None))
}
Some(selector) => {
let idx = selector.parse::<usize>().map_err(|_| {
HenError::new(HenErrorKind::Input, "Selector must be an integer")
.with_detail(format!("Received: {}", selector))
.with_exit_code(2)
})?;
let order = planner.order_for(idx).map_err(|err| {
HenError::new(HenErrorKind::Planner, "Failed to plan for selected request")
.with_detail(err.to_string())
})?;
Ok((order.clone(), vec![idx], Some(idx)))
}
None => {
if collection.requests.len() == 1 {
let order = planner.order_for(0).map_err(|err| {
HenError::new(HenErrorKind::Planner, "Failed to plan for the only request")
.with_detail(err.to_string())
})?;
Ok((order.clone(), vec![0], Some(0)))
} else {
let selection = request_prompt(collection);
let order = planner.order_for(selection).map_err(|err| {
HenError::new(HenErrorKind::Planner, "Failed to plan for selected request")
.with_detail(err.to_string())
})?;
Ok((order.clone(), vec![selection], Some(selection)))
}
}
}
}
fn resolve_execution_plan_non_interactive(
collection: &collection::Collection,
planner: &request::RequestPlanner,
selector: Option<&str>,
) -> HenResult<(Vec<usize>, Vec<usize>, Option<usize>)> {
match selector {
Some("all") => {
let order = planner.order_all();
Ok((order.clone(), order, None))
}
Some(selector) => {
let idx = selector.parse::<usize>().map_err(|_| {
HenError::new(HenErrorKind::Input, "Selector must be an integer or 'all'")
.with_detail(format!("Received: {}", selector))
.with_exit_code(2)
})?;
let order = planner.order_for(idx).map_err(|err| {
HenError::new(HenErrorKind::Planner, "Failed to plan for selected request")
.with_detail(err.to_string())
})?;
Ok((order.clone(), vec![idx], Some(idx)))
}
None => {
if collection.requests.len() == 1 {
let order = planner.order_for(0).map_err(|err| {
HenError::new(HenErrorKind::Planner, "Failed to plan for the only request")
.with_detail(err.to_string())
})?;
Ok((order.clone(), vec![0], Some(0)))
} else {
Err(HenError::new(
HenErrorKind::Input,
"A selector is required when a collection contains multiple requests",
)
.with_detail("Provide a request index or use 'all'.")
.with_exit_code(2))
}
}
}
}