added recipe_dir (#2543)
This commit is contained in:
Generated
+60
-6
@@ -2110,7 +2110,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
checksum = "7e5768da2206272c81ef0b5e951a41862938a6070da63bcea197899942d3b947"
|
checksum = "7e5768da2206272c81ef0b5e951a41862938a6070da63bcea197899942d3b947"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cfg-if",
|
"cfg-if",
|
||||||
"rustix",
|
"rustix 0.38.44",
|
||||||
"windows-sys 0.52.0",
|
"windows-sys 0.52.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
@@ -2123,6 +2123,18 @@ dependencies = [
|
|||||||
"simd-adler32",
|
"simd-adler32",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "filetime"
|
||||||
|
version = "0.2.25"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "35c0522e981e68cbfa8c3f978441a5f34b30b96e146b33cd3359176b50fe8586"
|
||||||
|
dependencies = [
|
||||||
|
"cfg-if",
|
||||||
|
"libc",
|
||||||
|
"libredox",
|
||||||
|
"windows-sys 0.59.0",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "flate2"
|
name = "flate2"
|
||||||
version = "1.1.0"
|
version = "1.1.0"
|
||||||
@@ -2611,6 +2623,7 @@ dependencies = [
|
|||||||
"serde_json",
|
"serde_json",
|
||||||
"serde_yaml",
|
"serde_yaml",
|
||||||
"shlex",
|
"shlex",
|
||||||
|
"tar",
|
||||||
"temp-env",
|
"temp-env",
|
||||||
"tempfile",
|
"tempfile",
|
||||||
"test-case",
|
"test-case",
|
||||||
@@ -3649,7 +3662,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
checksum = "fc2f4eb4bc735547cfed7c0a4922cbd04a4655978c09b54f1f7b228750664c34"
|
checksum = "fc2f4eb4bc735547cfed7c0a4922cbd04a4655978c09b54f1f7b228750664c34"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cfg-if",
|
"cfg-if",
|
||||||
"windows-targets 0.48.5",
|
"windows-targets 0.52.6",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -3660,6 +3673,7 @@ checksum = "c0ff37bd590ca25063e35af745c343cb7a0271906fb7b37e4813e8f79f00268d"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags 2.9.0",
|
"bitflags 2.9.0",
|
||||||
"libc",
|
"libc",
|
||||||
|
"redox_syscall",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -3686,6 +3700,12 @@ version = "0.4.15"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "d26c52dbd32dccf2d10cac7725f8eae5296885fb5703b261f7d0a0739ec807ab"
|
checksum = "d26c52dbd32dccf2d10cac7725f8eae5296885fb5703b261f7d0a0739ec807ab"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "linux-raw-sys"
|
||||||
|
version = "0.9.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "cd945864f07fe9f5371a27ad7b52a172b4b499999f1d97574c9fa68373937e12"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "litemap"
|
name = "litemap"
|
||||||
version = "0.7.5"
|
version = "0.7.5"
|
||||||
@@ -5209,7 +5229,20 @@ dependencies = [
|
|||||||
"bitflags 2.9.0",
|
"bitflags 2.9.0",
|
||||||
"errno",
|
"errno",
|
||||||
"libc",
|
"libc",
|
||||||
"linux-raw-sys",
|
"linux-raw-sys 0.4.15",
|
||||||
|
"windows-sys 0.59.0",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rustix"
|
||||||
|
version = "1.0.7"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "c71e83d6afe7ff64890ec6b71d6a69bb8a610ab78ce364b3352876bb4c801266"
|
||||||
|
dependencies = [
|
||||||
|
"bitflags 2.9.0",
|
||||||
|
"errno",
|
||||||
|
"libc",
|
||||||
|
"linux-raw-sys 0.9.4",
|
||||||
"windows-sys 0.59.0",
|
"windows-sys 0.59.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
@@ -5945,6 +5978,17 @@ dependencies = [
|
|||||||
"version-compare",
|
"version-compare",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "tar"
|
||||||
|
version = "0.4.44"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "1d863878d212c87a19c1a610eb53bb01fe12951c0501cf5a0d65f724914a667a"
|
||||||
|
dependencies = [
|
||||||
|
"filetime",
|
||||||
|
"libc",
|
||||||
|
"xattr",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "target-lexicon"
|
name = "target-lexicon"
|
||||||
version = "0.12.16"
|
version = "0.12.16"
|
||||||
@@ -5971,7 +6015,7 @@ dependencies = [
|
|||||||
"fastrand",
|
"fastrand",
|
||||||
"getrandom 0.3.1",
|
"getrandom 0.3.1",
|
||||||
"once_cell",
|
"once_cell",
|
||||||
"rustix",
|
"rustix 0.38.44",
|
||||||
"windows-sys 0.59.0",
|
"windows-sys 0.59.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
@@ -5990,7 +6034,7 @@ version = "0.4.1"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "5352447f921fda68cf61b4101566c0bdb5104eff6804d0678e5227580ab6a4e9"
|
checksum = "5352447f921fda68cf61b4101566c0bdb5104eff6804d0678e5227580ab6a4e9"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"rustix",
|
"rustix 0.38.44",
|
||||||
"windows-sys 0.59.0",
|
"windows-sys 0.59.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
@@ -7061,7 +7105,7 @@ dependencies = [
|
|||||||
"either",
|
"either",
|
||||||
"home",
|
"home",
|
||||||
"once_cell",
|
"once_cell",
|
||||||
"rustix",
|
"rustix 0.38.44",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -7535,6 +7579,16 @@ version = "0.5.5"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "1e9df38ee2d2c3c5948ea468a8406ff0db0b29ae1ffde1bcf20ef305bcc95c51"
|
checksum = "1e9df38ee2d2c3c5948ea468a8406ff0db0b29ae1ffde1bcf20ef305bcc95c51"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "xattr"
|
||||||
|
version = "1.5.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "0d65cbf2f12c15564212d48f4e3dfb87923d25d611f2aed18f4cb23f0413d89e"
|
||||||
|
dependencies = [
|
||||||
|
"libc",
|
||||||
|
"rustix 1.0.7",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "xcap"
|
name = "xcap"
|
||||||
version = "0.0.14"
|
version = "0.0.14"
|
||||||
|
|||||||
@@ -54,6 +54,7 @@ base64 = "0.22.1"
|
|||||||
regex = "1.11.1"
|
regex = "1.11.1"
|
||||||
minijinja = "2.8.0"
|
minijinja = "2.8.0"
|
||||||
nix = { version = "0.30.1", features = ["process", "signal"] }
|
nix = { version = "0.30.1", features = ["process", "signal"] }
|
||||||
|
tar = "0.4"
|
||||||
|
|
||||||
[target.'cfg(target_os = "windows")'.dependencies]
|
[target.'cfg(target_os = "windows")'.dependencies]
|
||||||
winapi = { version = "0.3", features = ["wincred"] }
|
winapi = { version = "0.3", features = ["wincred"] }
|
||||||
|
|||||||
@@ -1,14 +1,18 @@
|
|||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
|
use console::style;
|
||||||
use std::env;
|
use std::env;
|
||||||
|
use std::fs;
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
use std::process::Command;
|
use std::process::Command;
|
||||||
|
use std::process::Stdio;
|
||||||
|
use tar::Archive;
|
||||||
|
|
||||||
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> {
|
) -> Result<(String, PathBuf)> {
|
||||||
println!(
|
println!(
|
||||||
"retrieving recipe from github repo {}",
|
"retrieving recipe from github repo {}",
|
||||||
recipe_repo_full_name
|
recipe_repo_full_name
|
||||||
@@ -16,19 +20,22 @@ pub fn retrieve_recipe_from_github(
|
|||||||
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 file_extensions = ["yaml", "json"];
|
let file_extensions = ["yaml", "json"];
|
||||||
|
|
||||||
for ext in file_extensions {
|
for ext in file_extensions {
|
||||||
let file_path_in_repo = format!("{}/recipe.{}", recipe_name, ext);
|
let candidate_file_path = download_dir.join(format!("recipe.{}", ext));
|
||||||
match get_file_content_from_github(&local_repo_path, &file_path_in_repo) {
|
if candidate_file_path.exists() {
|
||||||
Ok(content) => {
|
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, file_path_in_repo
|
recipe_repo_full_name,
|
||||||
);
|
candidate_file_path
|
||||||
return Ok(content);
|
.strip_prefix(&download_dir)
|
||||||
}
|
.unwrap()
|
||||||
Err(_) => continue,
|
.display()
|
||||||
|
);
|
||||||
|
return Ok((content, download_dir));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Err(anyhow::anyhow!(
|
Err(anyhow::anyhow!(
|
||||||
@@ -38,28 +45,6 @@ pub fn retrieve_recipe_from_github(
|
|||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_file_content_from_github(
|
|
||||||
local_repo_path: &Path,
|
|
||||||
file_path_in_repo: &str,
|
|
||||||
) -> Result<String> {
|
|
||||||
let ref_and_path = format!("origin/main:{}", file_path_in_repo);
|
|
||||||
let error_message: String = format!(
|
|
||||||
"Failed to get content from {} in github repo",
|
|
||||||
file_path_in_repo
|
|
||||||
);
|
|
||||||
let output = Command::new("git")
|
|
||||||
.args(["show", &ref_and_path])
|
|
||||||
.current_dir(local_repo_path)
|
|
||||||
.output()
|
|
||||||
.map_err(|_: std::io::Error| anyhow::anyhow!(error_message.clone()))?;
|
|
||||||
|
|
||||||
if output.status.success() {
|
|
||||||
Ok(String::from_utf8_lossy(&output.stdout).to_string())
|
|
||||||
} else {
|
|
||||||
Err(anyhow::anyhow!(error_message.clone()))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn ensure_gh_authenticated() -> Result<()> {
|
fn ensure_gh_authenticated() -> Result<()> {
|
||||||
// Check authentication status
|
// Check authentication status
|
||||||
let status = Command::new("gh")
|
let status = Command::new("gh")
|
||||||
@@ -129,3 +114,41 @@ fn fetch_origin(local_repo_path: &Path) -> Result<()> {
|
|||||||
Err(anyhow::anyhow!(error_message))
|
Err(anyhow::anyhow!(error_message))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn get_folder_from_github(local_repo_path: &Path, recipe_name: &str) -> Result<PathBuf> {
|
||||||
|
let ref_and_path = format!("origin/main:{}", recipe_name);
|
||||||
|
let output_dir = env::temp_dir().join(recipe_name);
|
||||||
|
|
||||||
|
if output_dir.exists() {
|
||||||
|
fs::remove_dir_all(&output_dir)?;
|
||||||
|
}
|
||||||
|
fs::create_dir_all(&output_dir)?;
|
||||||
|
|
||||||
|
let archive_output = Command::new("git")
|
||||||
|
.args(["archive", &ref_and_path])
|
||||||
|
.current_dir(local_repo_path)
|
||||||
|
.stdout(Stdio::piped())
|
||||||
|
.spawn()?;
|
||||||
|
|
||||||
|
let stdout = archive_output
|
||||||
|
.stdout
|
||||||
|
.ok_or_else(|| anyhow::anyhow!("Failed to capture stdout from git archive"))?;
|
||||||
|
|
||||||
|
let mut archive = Archive::new(stdout);
|
||||||
|
archive.unpack(&output_dir)?;
|
||||||
|
list_files(&output_dir)?;
|
||||||
|
|
||||||
|
Ok(output_dir)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn list_files(dir: &Path) -> Result<()> {
|
||||||
|
println!("{}", style("Files downloaded from github:").bold());
|
||||||
|
for entry in fs::read_dir(dir)? {
|
||||||
|
let entry = entry?;
|
||||||
|
let path = entry.path();
|
||||||
|
if path.is_file() {
|
||||||
|
println!(" - {}", path.display());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|||||||
@@ -3,6 +3,8 @@ use std::collections::HashMap;
|
|||||||
use console::style;
|
use console::style;
|
||||||
use goose::recipe::Recipe;
|
use goose::recipe::Recipe;
|
||||||
|
|
||||||
|
use crate::recipes::recipe::BUILT_IN_RECIPE_DIR_PARAM;
|
||||||
|
|
||||||
pub fn print_recipe_explanation(recipe: &Recipe) {
|
pub fn print_recipe_explanation(recipe: &Recipe) {
|
||||||
println!(
|
println!(
|
||||||
"{} {}",
|
"{} {}",
|
||||||
@@ -33,6 +35,17 @@ pub fn print_recipe_explanation(recipe: &Recipe) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn print_parameters_with_values(params: HashMap<String, String>) {
|
||||||
|
for (key, value) in params {
|
||||||
|
let label = if key == BUILT_IN_RECIPE_DIR_PARAM {
|
||||||
|
" (built-in)"
|
||||||
|
} else {
|
||||||
|
""
|
||||||
|
};
|
||||||
|
println!(" {}{}: {}", key, label, value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn print_required_parameters_for_template(
|
pub fn print_required_parameters_for_template(
|
||||||
params_for_template: HashMap<String, String>,
|
params_for_template: HashMap<String, String>,
|
||||||
missing_params: Vec<String>,
|
missing_params: Vec<String>,
|
||||||
@@ -42,9 +55,7 @@ pub fn print_required_parameters_for_template(
|
|||||||
"{}",
|
"{}",
|
||||||
style("📥 Parameters used to load this recipe:").bold()
|
style("📥 Parameters used to load this recipe:").bold()
|
||||||
);
|
);
|
||||||
for (key, value) in params_for_template {
|
print_parameters_with_values(params_for_template)
|
||||||
println!(" {}: {}", key, value);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if !missing_params.is_empty() {
|
if !missing_params.is_empty() {
|
||||||
println!(
|
println!(
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ use anyhow::Result;
|
|||||||
use console::style;
|
use console::style;
|
||||||
|
|
||||||
use crate::recipes::print_recipe::{
|
use crate::recipes::print_recipe::{
|
||||||
missing_parameters_command_line, print_recipe_explanation,
|
missing_parameters_command_line, print_parameters_with_values, print_recipe_explanation,
|
||||||
print_required_parameters_for_template,
|
print_required_parameters_for_template,
|
||||||
};
|
};
|
||||||
use crate::recipes::search_recipe::retrieve_recipe_file;
|
use crate::recipes::search_recipe::retrieve_recipe_file;
|
||||||
@@ -11,7 +11,9 @@ use minijinja::{Environment, Error, Template, UndefinedBehavior};
|
|||||||
use serde_json::Value as JsonValue;
|
use serde_json::Value as JsonValue;
|
||||||
use serde_yaml::Value as YamlValue;
|
use serde_yaml::Value as YamlValue;
|
||||||
use std::collections::{HashMap, HashSet};
|
use std::collections::{HashMap, HashSet};
|
||||||
|
use std::path::PathBuf;
|
||||||
|
|
||||||
|
pub const BUILT_IN_RECIPE_DIR_PARAM: &str = "recipe_dir";
|
||||||
/// 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
|
||||||
@@ -29,12 +31,12 @@ use std::collections::{HashMap, HashSet};
|
|||||||
/// - Recipe is not valid
|
/// - Recipe is not valid
|
||||||
/// - The required fields are missing
|
/// - The required fields are missing
|
||||||
pub fn load_recipe_as_template(recipe_name: &str, params: Vec<(String, String)>) -> Result<Recipe> {
|
pub fn load_recipe_as_template(recipe_name: &str, params: Vec<(String, String)>) -> Result<Recipe> {
|
||||||
let recipe_file_content = retrieve_recipe_file(recipe_name)?;
|
let (recipe_file_content, recipe_parent_dir) = retrieve_recipe_file(recipe_name)?;
|
||||||
|
|
||||||
let recipe = validate_recipe_file_parameters(&recipe_file_content)?;
|
let recipe = validate_recipe_file_parameters(&recipe_file_content)?;
|
||||||
|
|
||||||
let (params_for_template, missing_params) =
|
let (params_for_template, missing_params) =
|
||||||
apply_values_to_parameters(¶ms, recipe.parameters, true)?;
|
apply_values_to_parameters(¶ms, recipe.parameters, recipe_parent_dir, true)?;
|
||||||
if !missing_params.is_empty() {
|
if !missing_params.is_empty() {
|
||||||
return Err(anyhow::anyhow!(
|
return Err(anyhow::anyhow!(
|
||||||
"Please provide the following parameters in the command line: {}",
|
"Please provide the following parameters in the command line: {}",
|
||||||
@@ -56,9 +58,7 @@ pub fn load_recipe_as_template(recipe_name: &str, params: Vec<(String, String)>)
|
|||||||
|
|
||||||
if !params_for_template.is_empty() {
|
if !params_for_template.is_empty() {
|
||||||
println!("{}", style("Parameters used to load this recipe:").bold());
|
println!("{}", style("Parameters used to load this recipe:").bold());
|
||||||
for (key, value) in params_for_template {
|
print_parameters_with_values(params_for_template);
|
||||||
println!("{}: {}", key, value);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
println!();
|
println!();
|
||||||
Ok(recipe)
|
Ok(recipe)
|
||||||
@@ -83,7 +83,7 @@ pub fn load_recipe_as_template(recipe_name: &str, params: Vec<(String, String)>)
|
|||||||
/// - The YAML/JSON is invalid
|
/// - The YAML/JSON is invalid
|
||||||
/// - The parameter definition does not match the template variables in the recipe file
|
/// - The parameter definition does not match the template variables in the recipe file
|
||||||
pub fn load_recipe(recipe_name: &str) -> Result<Recipe> {
|
pub fn load_recipe(recipe_name: &str) -> Result<Recipe> {
|
||||||
let recipe_file_content = retrieve_recipe_file(recipe_name)?;
|
let (recipe_file_content, _) = retrieve_recipe_file(recipe_name)?;
|
||||||
|
|
||||||
validate_recipe_file_parameters(&recipe_file_content)
|
validate_recipe_file_parameters(&recipe_file_content)
|
||||||
}
|
}
|
||||||
@@ -92,13 +92,13 @@ pub fn explain_recipe_with_parameters(
|
|||||||
recipe_name: &str,
|
recipe_name: &str,
|
||||||
params: Vec<(String, String)>,
|
params: Vec<(String, String)>,
|
||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
let recipe_file_content = retrieve_recipe_file(recipe_name)?;
|
let (recipe_file_content, recipe_parent_dir) = retrieve_recipe_file(recipe_name)?;
|
||||||
|
|
||||||
let raw_recipe = validate_recipe_file_parameters(&recipe_file_content)?;
|
let raw_recipe = validate_recipe_file_parameters(&recipe_file_content)?;
|
||||||
print_recipe_explanation(&raw_recipe);
|
print_recipe_explanation(&raw_recipe);
|
||||||
let recipe_parameters = raw_recipe.parameters;
|
let recipe_parameters = raw_recipe.parameters;
|
||||||
let (params_for_template, missing_params) =
|
let (params_for_template, missing_params) =
|
||||||
apply_values_to_parameters(¶ms, recipe_parameters, false)?;
|
apply_values_to_parameters(¶ms, recipe_parameters, recipe_parent_dir, false)?;
|
||||||
print_required_parameters_for_template(params_for_template, missing_params);
|
print_required_parameters_for_template(params_for_template, missing_params);
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
@@ -115,7 +115,8 @@ fn validate_parameters_in_template(
|
|||||||
recipe_parameters: &Option<Vec<RecipeParameter>>,
|
recipe_parameters: &Option<Vec<RecipeParameter>>,
|
||||||
recipe_file_content: &str,
|
recipe_file_content: &str,
|
||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
let template_variables = extract_template_variables(recipe_file_content)?;
|
let mut template_variables = extract_template_variables(recipe_file_content)?;
|
||||||
|
template_variables.remove(BUILT_IN_RECIPE_DIR_PARAM);
|
||||||
|
|
||||||
let param_keys: HashSet<String> = recipe_parameters
|
let param_keys: HashSet<String> = recipe_parameters
|
||||||
.as_ref()
|
.as_ref()
|
||||||
@@ -207,9 +208,17 @@ fn extract_template_variables(template_str: &str) -> Result<HashSet<String>> {
|
|||||||
fn apply_values_to_parameters(
|
fn apply_values_to_parameters(
|
||||||
user_params: &[(String, String)],
|
user_params: &[(String, String)],
|
||||||
recipe_parameters: Option<Vec<RecipeParameter>>,
|
recipe_parameters: Option<Vec<RecipeParameter>>,
|
||||||
|
recipe_parent_dir: PathBuf,
|
||||||
enable_user_prompt: bool,
|
enable_user_prompt: bool,
|
||||||
) -> Result<(HashMap<String, String>, Vec<String>)> {
|
) -> Result<(HashMap<String, String>, Vec<String>)> {
|
||||||
let mut param_map: HashMap<String, String> = user_params.iter().cloned().collect();
|
let mut param_map: HashMap<String, String> = user_params.iter().cloned().collect();
|
||||||
|
let recipe_parent_dir_str = recipe_parent_dir
|
||||||
|
.to_str()
|
||||||
|
.ok_or_else(|| anyhow::anyhow!("Invalid UTF-8 in recipe_dir"))?;
|
||||||
|
param_map.insert(
|
||||||
|
BUILT_IN_RECIPE_DIR_PARAM.to_string(),
|
||||||
|
recipe_parent_dir_str.to_string(),
|
||||||
|
);
|
||||||
let mut missing_params: Vec<String> = Vec::new();
|
let mut missing_params: Vec<String> = Vec::new();
|
||||||
for param in recipe_parameters.unwrap_or_default() {
|
for param in recipe_parameters.unwrap_or_default() {
|
||||||
if !param_map.contains_key(¶m.key) {
|
if !param_map.contains_key(¶m.key) {
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
use anyhow::{anyhow, Context, Result};
|
use anyhow::{anyhow, Result};
|
||||||
use goose::config::Config;
|
use goose::config::Config;
|
||||||
use std::fs;
|
use std::fs;
|
||||||
use std::path::{Path, PathBuf};
|
use std::path::{Path, PathBuf};
|
||||||
|
|
||||||
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};
|
||||||
|
|
||||||
pub fn retrieve_recipe_file(recipe_name: &str) -> Result<String> {
|
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 path
|
||||||
if recipe_name.ends_with(".yaml") || recipe_name.ends_with(".json") {
|
if recipe_name.ends_with(".yaml") || recipe_name.ends_with(".json") {
|
||||||
let path = PathBuf::from(recipe_name);
|
let path = PathBuf::from(recipe_name);
|
||||||
@@ -14,8 +14,8 @@ pub fn retrieve_recipe_file(recipe_name: &str) -> Result<String> {
|
|||||||
|
|
||||||
// First check current directory
|
// First check current directory
|
||||||
let current_dir = std::env::current_dir()?;
|
let current_dir = std::env::current_dir()?;
|
||||||
if let Ok(content) = read_recipe_in_dir(¤t_dir, recipe_name) {
|
if let Ok((content, recipe_parent_dir)) = read_recipe_in_dir(¤t_dir, recipe_name) {
|
||||||
return Ok(content);
|
return Ok((content, recipe_parent_dir));
|
||||||
}
|
}
|
||||||
read_recipe_in_dir(¤t_dir, recipe_name).or_else(|e| {
|
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() {
|
||||||
@@ -34,23 +34,33 @@ fn configured_github_recipe_repo() -> Option<String> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn read_recipe_file<P: AsRef<Path>>(recipe_path: P) -> Result<String> {
|
fn read_recipe_file<P: AsRef<Path>>(recipe_path: P) -> Result<(String, PathBuf)> {
|
||||||
let path = recipe_path.as_ref();
|
let path = recipe_path.as_ref();
|
||||||
|
|
||||||
if path.exists() {
|
let content = fs::read_to_string(path)
|
||||||
let content = fs::read_to_string(path)
|
.map_err(|e| anyhow!("Failed to read recipe file {}: {}", path.display(), e))?;
|
||||||
.with_context(|| format!("Failed to read recipe file: {}", path.display()))?;
|
|
||||||
Ok(content)
|
let canonical = path.canonicalize().map_err(|e| {
|
||||||
} else {
|
anyhow!(
|
||||||
Err(anyhow!("Recipe file not found: {}", path.display()))
|
"Failed to resolve absolute path for {}: {}",
|
||||||
}
|
path.display(),
|
||||||
|
e
|
||||||
|
)
|
||||||
|
})?;
|
||||||
|
|
||||||
|
let parent_dir = canonical
|
||||||
|
.parent()
|
||||||
|
.ok_or_else(|| anyhow!("Resolved path has no parent: {}", canonical.display()))?
|
||||||
|
.to_path_buf();
|
||||||
|
|
||||||
|
Ok((content, parent_dir))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn read_recipe_in_dir(dir: &Path, recipe_name: &str) -> Result<String> {
|
fn read_recipe_in_dir(dir: &Path, recipe_name: &str) -> Result<(String, PathBuf)> {
|
||||||
for ext in &["yaml", "json"] {
|
for ext in &["yaml", "json"] {
|
||||||
let recipe_path = dir.join(format!("{}.{}", recipe_name, ext));
|
let recipe_path = dir.join(format!("{}.{}", recipe_name, ext));
|
||||||
match read_recipe_file(recipe_path) {
|
match read_recipe_file(recipe_path) {
|
||||||
Ok(content) => return Ok(content),
|
Ok((content, recipe_parent_dir)) => return Ok((content, recipe_parent_dir)),
|
||||||
Err(_) => continue,
|
Err(_) => continue,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user