diff --git a/kclvm/driver/src/kpm_update.rs b/kclvm/driver/src/kpm_update.rs new file mode 100644 index 000000000..7835bf018 --- /dev/null +++ b/kclvm/driver/src/kpm_update.rs @@ -0,0 +1,54 @@ +use crate::kpm_metadata::get_path_for_executable; +use anyhow::{bail, Result}; +use std::{path::PathBuf, process::Command}; + +const MANIFEST_FILE: &str = "kcl.mod"; + +pub(crate) fn update_kcl_module(manifest_path: PathBuf) -> Result<()> { + match lookup_the_nearest_file_dir(manifest_path.clone(), MANIFEST_FILE) { + Some(mod_dir) => { + match Command::new(kcl()) + .arg("mod") + .arg("update") + .current_dir(mod_dir) + .output() + { + Ok(output) => { + if !output.status.success() { + bail!( + "update failed with error: {}", + String::from_utf8_lossy(&output.stderr) + ); + } + Ok(()) + } + Err(err) => bail!("update failed with error: {}", err), + } + } + None => bail!( + "Manifest file '{}' not found in directory hierarchy", + MANIFEST_FILE + ), + } +} +pub fn kcl() -> PathBuf { + get_path_for_executable("kcl") +} + +pub(crate) fn lookup_the_nearest_file_dir( + from: PathBuf, + the_nearest_file: &str, +) -> Option { + let mut current_dir = from; + + loop { + let found_path = current_dir.join(the_nearest_file); + if found_path.is_file() { + return current_dir.canonicalize().ok(); + } + match current_dir.parent() { + Some(parent) => current_dir = parent.to_path_buf(), + None => return None, + } + } +} diff --git a/kclvm/driver/src/lib.rs b/kclvm/driver/src/lib.rs index a454f65d2..9a2f15e55 100644 --- a/kclvm/driver/src/lib.rs +++ b/kclvm/driver/src/lib.rs @@ -1,6 +1,7 @@ use anyhow::Result; pub mod arguments; pub mod kpm_metadata; +pub mod kpm_update; pub const DEFAULT_PROJECT_FILE: &str = "project.yaml"; #[cfg(test)] diff --git a/kclvm/driver/src/tests.rs b/kclvm/driver/src/tests.rs index 2d218f393..279f1cb3c 100644 --- a/kclvm/driver/src/tests.rs +++ b/kclvm/driver/src/tests.rs @@ -1,3 +1,4 @@ +use super::*; use std::path::{Path, PathBuf}; use std::{env, fs, panic}; @@ -8,6 +9,7 @@ use walkdir::WalkDir; use crate::arguments::parse_key_value_pair; use crate::kpm_metadata::{fetch_metadata, fill_pkg_maps_for_k_file, lookup_the_nearest_file_dir}; +use crate::kpm_update::update_kcl_module; use crate::{canonicalize_input_files, expand_input_files, get_pkg_list}; #[test] @@ -379,3 +381,29 @@ fn test_get_pkg_list() { 3 ); } + +#[cfg(test)] +// Define a mock structure to simulate the behavior of Command::output +struct MockCommand { + output: Result, +} +// Define a mock structure to represent the output of Command::output +struct MockCommandOutput { + status: std::process::ExitStatus, + stderr: Vec, +} + +#[test] +fn test_update_kcl_module_failure() { + let manifest_path = PathBuf::from("path/to/manifest"); + fn mock_command_new_failing(_command: &str) -> MockCommand { + MockCommand { + output: Err(std::io::Error::new( + std::io::ErrorKind::Other, + "Command failed", + )), + } + } + let result = update_kcl_module(manifest_path); + assert!(result.is_err()); +}