fix(function): build bundled bash tools without writing back to the source tree

PR #24 follow-up 1. The bundled-tools test called the writing
generate_bash_declarations on the repo's assets/functions/tools/*.sh,
so cargo test could rewrite tracked files. Split the build+export step
into a pure build_bash_tool so the test never touches the source tree.
This commit is contained in:
Dark-Alex-17 committed 2026-09-11 10:56:27 -06:00
1 parent b65aa76d2d
commit 2f839b332d
2 files changed
+17 -7

No files matched your search

+2 -1
View File
@@ -3389,7 +3389,8 @@ mod tests {
continue; continue;
} }
let name = path.file_stem().unwrap().to_string_lossy().to_string(); let name = path.file_stem().unwrap().to_string_lossy().to_string();
let declarations = Functions::generate_declarations(&path) let src = std::fs::read_to_string(&path).unwrap();
let (_, declarations) = bash::build_bash_tool(&src, &name)
.unwrap_or_else(|e| panic!("bundled tool '{name}' failed to parse: {e}")); .unwrap_or_else(|e| panic!("bundled tool '{name}' failed to parse: {e}"));
assert!( assert!(
!declarations.is_empty(), !declarations.is_empty(),
+15 -6
View File
@@ -18,23 +18,32 @@ pub fn generate_bash_declarations(
.with_context(|| format!("Failed to load script at '{tool_file:?}'"))?; .with_context(|| format!("Failed to load script at '{tool_file:?}'"))?;
debug!("Building script at '{tool_file:?}'"); debug!("Building script at '{tool_file:?}'");
let (build_script, declarations) = build_bash_tool(&src, file_name)
.with_context(|| format!("Failed to build script at '{tools_file_path:?}'"))?;
function::write_file_atomic(tools_file_path, &build_script, Some(0o755))
.with_context(|| format!("Failed to write built script to '{tools_file_path:?}'"))?;
Ok(declarations)
}
/// Builds the argc script and derives its declarations without touching the
/// filesystem, so callers can inspect a tool source without rewriting it.
pub fn build_bash_tool(src: &str, file_name: &str) -> Result<(String, Vec<FunctionDeclaration>)> {
let build_script = argc::build( let build_script = argc::build(
&src, src,
"", "",
env::var("TERM_WIDTH").ok().and_then(|v| v.parse().ok()), env::var("TERM_WIDTH").ok().and_then(|v| v.parse().ok()),
)?; )?;
let build_script = allow_empty_required_values(&build_script); let build_script = allow_empty_required_values(&build_script);
function::write_file_atomic(tools_file_path, &build_script, Some(0o755))
.with_context(|| format!("Failed to write built script to '{tools_file_path:?}'"))?;
let command_value = argc::export(&build_script, file_name) let command_value = argc::export(&build_script, file_name)
.with_context(|| format!("Failed to parse script at '{tool_file:?}'"))?; .with_context(|| format!("Failed to parse script '{file_name}'"))?;
if command_value.subcommands.is_empty() { if command_value.subcommands.is_empty() {
let function_declaration = let function_declaration =
command_to_function_declaration(&command_value).ok_or_else(|| { command_to_function_declaration(&command_value).ok_or_else(|| {
anyhow::format_err!("Tool definition missing or empty description: {file_name}") anyhow::format_err!("Tool definition missing or empty description: {file_name}")
})?; })?;
Ok(vec![function_declaration]) Ok((build_script, vec![function_declaration]))
} else { } else {
let mut declarations = vec![]; let mut declarations = vec![];
for subcommand in &command_value.subcommands { for subcommand in &command_value.subcommands {
@@ -54,7 +63,7 @@ pub fn generate_bash_declarations(
} }
} }
Ok(declarations) Ok((build_script, declarations))
} }
} }