mirror of
https://github.com/aljazceru/goose.git
synced 2026-02-23 07:24:24 +01:00
feat: discover recipe in the paths from environment variable GOOSE_RECIPE_PATH (#2561)
This commit is contained in:
@@ -8,27 +8,28 @@ use std::process::Command;
|
||||
use std::process::Stdio;
|
||||
use tar::Archive;
|
||||
|
||||
use crate::recipes::recipe::RECIPE_FILE_EXTENSIONS;
|
||||
|
||||
pub const GOOSE_RECIPE_GITHUB_REPO_CONFIG_KEY: &str = "GOOSE_RECIPE_GITHUB_REPO";
|
||||
pub fn retrieve_recipe_from_github(
|
||||
recipe_name: &str,
|
||||
recipe_repo_full_name: &str,
|
||||
) -> Result<(String, PathBuf)> {
|
||||
println!(
|
||||
"retrieving recipe from github repo {}",
|
||||
recipe_repo_full_name
|
||||
"📦 Looking for recipe \"{}\" in github repo: {}",
|
||||
recipe_name, recipe_repo_full_name
|
||||
);
|
||||
ensure_gh_authenticated()?;
|
||||
let local_repo_path = ensure_repo_cloned(recipe_repo_full_name)?;
|
||||
fetch_origin(&local_repo_path)?;
|
||||
let download_dir = get_folder_from_github(&local_repo_path, recipe_name)?;
|
||||
let file_extensions = ["yaml", "json"];
|
||||
|
||||
for ext in file_extensions {
|
||||
for ext in RECIPE_FILE_EXTENSIONS {
|
||||
let candidate_file_path = download_dir.join(format!("recipe.{}", ext));
|
||||
if candidate_file_path.exists() {
|
||||
let content = std::fs::read_to_string(&candidate_file_path)?;
|
||||
println!(
|
||||
"retrieved recipe from github repo {}/{}",
|
||||
"⬇️ Retrieved recipe from github repo {}/{}",
|
||||
recipe_repo_full_name,
|
||||
candidate_file_path
|
||||
.strip_prefix(&download_dir)
|
||||
|
||||
@@ -14,6 +14,7 @@ use std::collections::{HashMap, HashSet};
|
||||
use std::path::PathBuf;
|
||||
|
||||
pub const BUILT_IN_RECIPE_DIR_PARAM: &str = "recipe_dir";
|
||||
pub const RECIPE_FILE_EXTENSIONS: &[&str] = &["yaml", "json"];
|
||||
/// Loads, validates a recipe from a YAML or JSON file, and renders it with the given parameters
|
||||
///
|
||||
/// # Arguments
|
||||
|
||||
@@ -1,23 +1,24 @@
|
||||
use anyhow::{anyhow, Result};
|
||||
use goose::config::Config;
|
||||
use std::fs;
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::{env, fs};
|
||||
|
||||
use crate::recipes::recipe::RECIPE_FILE_EXTENSIONS;
|
||||
|
||||
use super::github_recipe::{retrieve_recipe_from_github, GOOSE_RECIPE_GITHUB_REPO_CONFIG_KEY};
|
||||
|
||||
const GOOSE_RECIPE_PATH_ENV_VAR: &str = "GOOSE_RECIPE_PATH";
|
||||
|
||||
pub fn retrieve_recipe_file(recipe_name: &str) -> Result<(String, PathBuf)> {
|
||||
// If recipe_name ends with yaml or json, treat it as a direct path
|
||||
if recipe_name.ends_with(".yaml") || recipe_name.ends_with(".json") {
|
||||
// If recipe_name ends with yaml or json, treat it as a direct file path
|
||||
if RECIPE_FILE_EXTENSIONS
|
||||
.iter()
|
||||
.any(|ext| recipe_name.ends_with(&format!(".{}", ext)))
|
||||
{
|
||||
let path = PathBuf::from(recipe_name);
|
||||
return read_recipe_file(path);
|
||||
}
|
||||
|
||||
// First check current directory
|
||||
let current_dir = std::env::current_dir()?;
|
||||
if let Ok((content, recipe_parent_dir)) = read_recipe_in_dir(¤t_dir, recipe_name) {
|
||||
return Ok((content, recipe_parent_dir));
|
||||
}
|
||||
read_recipe_in_dir(¤t_dir, recipe_name).or_else(|e| {
|
||||
retrieve_recipe_from_local_path(recipe_name).or_else(|e| {
|
||||
if let Some(recipe_repo_full_name) = configured_github_recipe_repo() {
|
||||
retrieve_recipe_from_github(recipe_name, &recipe_repo_full_name)
|
||||
} else {
|
||||
@@ -26,6 +27,49 @@ pub fn retrieve_recipe_file(recipe_name: &str) -> Result<(String, PathBuf)> {
|
||||
})
|
||||
}
|
||||
|
||||
fn read_recipe_in_dir(dir: &Path, recipe_name: &str) -> Result<(String, PathBuf)> {
|
||||
for ext in RECIPE_FILE_EXTENSIONS {
|
||||
let recipe_path = dir.join(format!("{}.{}", recipe_name, ext));
|
||||
if let Ok(result) = read_recipe_file(recipe_path) {
|
||||
return Ok(result);
|
||||
}
|
||||
}
|
||||
Err(anyhow!(format!(
|
||||
"No {}.yaml or {}.json recipe file found in directory: {}",
|
||||
recipe_name,
|
||||
recipe_name,
|
||||
dir.display()
|
||||
)))
|
||||
}
|
||||
|
||||
fn retrieve_recipe_from_local_path(recipe_name: &str) -> Result<(String, PathBuf)> {
|
||||
let mut search_dirs = vec![PathBuf::from(".")];
|
||||
if let Ok(recipe_path_env) = env::var(GOOSE_RECIPE_PATH_ENV_VAR) {
|
||||
let path_separator = if cfg!(windows) { ';' } else { ':' };
|
||||
let recipe_path_env_dirs: Vec<PathBuf> = recipe_path_env
|
||||
.split(path_separator)
|
||||
.map(PathBuf::from)
|
||||
.collect();
|
||||
search_dirs.extend(recipe_path_env_dirs);
|
||||
}
|
||||
for dir in &search_dirs {
|
||||
if let Ok(result) = read_recipe_in_dir(dir, recipe_name) {
|
||||
return Ok(result);
|
||||
}
|
||||
}
|
||||
let search_dirs_str = search_dirs
|
||||
.iter()
|
||||
.map(|p| p.to_string_lossy())
|
||||
.collect::<Vec<_>>()
|
||||
.join(":");
|
||||
Err(anyhow!(
|
||||
"ℹ️ Failed to retrieve {}.yaml or {}.json in {}",
|
||||
recipe_name,
|
||||
recipe_name,
|
||||
search_dirs_str
|
||||
))
|
||||
}
|
||||
|
||||
fn configured_github_recipe_repo() -> Option<String> {
|
||||
let config = Config::global();
|
||||
match config.get_param(GOOSE_RECIPE_GITHUB_REPO_CONFIG_KEY) {
|
||||
@@ -55,17 +99,3 @@ fn read_recipe_file<P: AsRef<Path>>(recipe_path: P) -> Result<(String, PathBuf)>
|
||||
|
||||
Ok((content, parent_dir))
|
||||
}
|
||||
|
||||
fn read_recipe_in_dir(dir: &Path, recipe_name: &str) -> Result<(String, PathBuf)> {
|
||||
for ext in &["yaml", "json"] {
|
||||
let recipe_path = dir.join(format!("{}.{}", recipe_name, ext));
|
||||
match read_recipe_file(recipe_path) {
|
||||
Ok((content, recipe_parent_dir)) => return Ok((content, recipe_parent_dir)),
|
||||
Err(_) => continue,
|
||||
}
|
||||
}
|
||||
Err(anyhow!(format!(
|
||||
"No {}.yaml or {}.json recipe file found in current directory.",
|
||||
recipe_name, recipe_name
|
||||
)))
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user