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 std::process::Stdio;
|
||||||
use tar::Archive;
|
use tar::Archive;
|
||||||
|
|
||||||
|
use crate::recipes::recipe::RECIPE_FILE_EXTENSIONS;
|
||||||
|
|
||||||
pub const GOOSE_RECIPE_GITHUB_REPO_CONFIG_KEY: &str = "GOOSE_RECIPE_GITHUB_REPO";
|
pub const GOOSE_RECIPE_GITHUB_REPO_CONFIG_KEY: &str = "GOOSE_RECIPE_GITHUB_REPO";
|
||||||
pub fn retrieve_recipe_from_github(
|
pub fn retrieve_recipe_from_github(
|
||||||
recipe_name: &str,
|
recipe_name: &str,
|
||||||
recipe_repo_full_name: &str,
|
recipe_repo_full_name: &str,
|
||||||
) -> Result<(String, PathBuf)> {
|
) -> Result<(String, PathBuf)> {
|
||||||
println!(
|
println!(
|
||||||
"retrieving recipe from github repo {}",
|
"📦 Looking for recipe \"{}\" in github repo: {}",
|
||||||
recipe_repo_full_name
|
recipe_name, recipe_repo_full_name
|
||||||
);
|
);
|
||||||
ensure_gh_authenticated()?;
|
ensure_gh_authenticated()?;
|
||||||
let local_repo_path = ensure_repo_cloned(recipe_repo_full_name)?;
|
let local_repo_path = ensure_repo_cloned(recipe_repo_full_name)?;
|
||||||
fetch_origin(&local_repo_path)?;
|
fetch_origin(&local_repo_path)?;
|
||||||
let download_dir = get_folder_from_github(&local_repo_path, recipe_name)?;
|
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));
|
let candidate_file_path = download_dir.join(format!("recipe.{}", ext));
|
||||||
if candidate_file_path.exists() {
|
if candidate_file_path.exists() {
|
||||||
let content = std::fs::read_to_string(&candidate_file_path)?;
|
let content = std::fs::read_to_string(&candidate_file_path)?;
|
||||||
println!(
|
println!(
|
||||||
"retrieved recipe from github repo {}/{}",
|
"⬇️ Retrieved recipe from github repo {}/{}",
|
||||||
recipe_repo_full_name,
|
recipe_repo_full_name,
|
||||||
candidate_file_path
|
candidate_file_path
|
||||||
.strip_prefix(&download_dir)
|
.strip_prefix(&download_dir)
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ use std::collections::{HashMap, HashSet};
|
|||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
|
|
||||||
pub const BUILT_IN_RECIPE_DIR_PARAM: &str = "recipe_dir";
|
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
|
/// Loads, validates a recipe from a YAML or JSON file, and renders it with the given parameters
|
||||||
///
|
///
|
||||||
/// # Arguments
|
/// # Arguments
|
||||||
|
|||||||
@@ -1,23 +1,24 @@
|
|||||||
use anyhow::{anyhow, Result};
|
use anyhow::{anyhow, Result};
|
||||||
use goose::config::Config;
|
use goose::config::Config;
|
||||||
use std::fs;
|
|
||||||
use std::path::{Path, PathBuf};
|
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};
|
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)> {
|
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 or json, treat it as a direct file path
|
||||||
if recipe_name.ends_with(".yaml") || recipe_name.ends_with(".json") {
|
if RECIPE_FILE_EXTENSIONS
|
||||||
|
.iter()
|
||||||
|
.any(|ext| recipe_name.ends_with(&format!(".{}", ext)))
|
||||||
|
{
|
||||||
let path = PathBuf::from(recipe_name);
|
let path = PathBuf::from(recipe_name);
|
||||||
return read_recipe_file(path);
|
return read_recipe_file(path);
|
||||||
}
|
}
|
||||||
|
retrieve_recipe_from_local_path(recipe_name).or_else(|e| {
|
||||||
// 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| {
|
|
||||||
if let Some(recipe_repo_full_name) = configured_github_recipe_repo() {
|
if let Some(recipe_repo_full_name) = configured_github_recipe_repo() {
|
||||||
retrieve_recipe_from_github(recipe_name, &recipe_repo_full_name)
|
retrieve_recipe_from_github(recipe_name, &recipe_repo_full_name)
|
||||||
} else {
|
} 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> {
|
fn configured_github_recipe_repo() -> Option<String> {
|
||||||
let config = Config::global();
|
let config = Config::global();
|
||||||
match config.get_param(GOOSE_RECIPE_GITHUB_REPO_CONFIG_KEY) {
|
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))
|
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