use std::io::Read;
use anyhow::{anyhow, Context as _, Result};
use camino::Utf8PathBuf;
use clap::{Args, Subcommand};
use cooklang_fs::{resolve_recipe, FsIndex};
use crate::{Context, Input};
use self::read::ReadArgs;
mod ast;
mod check;
mod list;
mod read;
#[derive(Debug, Args)]
#[command(args_conflicts_with_subcommands = true)]
pub struct RecipeArgs {
#[command(subcommand)]
command: Option<RecipeCommand>,
#[command(flatten)]
read_args: ReadArgs,
}
#[derive(Debug, Subcommand)]
enum RecipeCommand {
#[command(alias = "r")]
Read(ReadArgs),
#[command(alias = "c")]
Check(check::CheckArgs),
#[command(alias = "l")]
List(list::ListArgs),
Ast(ast::AstArgs),
}
pub fn run(ctx: &Context, args: RecipeArgs) -> Result<()> {
let command = args.command.unwrap_or(RecipeCommand::Read(args.read_args));
match command {
RecipeCommand::Read(args) => read::run(ctx, args),
RecipeCommand::Check(args) => check::run(ctx, args),
RecipeCommand::List(args) => list::run(ctx, args),
RecipeCommand::Ast(args) => ast::run(ctx, args),
}
}
#[derive(Debug, Args)]
struct RecipeInputArgs {
recipe: Option<Utf8PathBuf>,
#[arg(short, long, required_unless_present = "recipe")]
name: Option<String>,
}
impl RecipeInputArgs {
pub fn read(&self, index: &FsIndex) -> Result<Input> {
let input = if let Some(query) = &self.recipe {
let entry = resolve_recipe(query.as_str(), index, None)?;
Input::File {
content: entry.read()?,
override_name: self.name.clone(),
}
} else {
let mut buf = String::new();
std::io::stdin()
.read_to_string(&mut buf)
.context("Failed to read stdin")?;
Input::Stdin {
text: buf,
recipe_name: self.name.clone().ok_or(anyhow!("No name for recipe"))?,
}
};
Ok(input)
}
}