From 257e9bb5293a85a1a3eab5374ca46787e58b77f6 Mon Sep 17 00:00:00 2001 From: sagie gur ari Date: Sat, 19 Oct 2024 07:03:23 +0000 Subject: [PATCH] adding git root support #1175 --- CHANGELOG.md | 2 +- docs/_includes/content.md | 8 +++++-- examples/extends_list.toml | 2 ++ src/lib/descriptor/mod.rs | 26 ++++++++++++++++---- src/lib/descriptor/mod_test.rs | 44 ++++++++++++++++++++++++++++++++++ src/lib/environment/mod.rs | 25 +++++++++++++++++++ src/lib/types.rs | 4 ++-- 7 files changed, 101 insertions(+), 10 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a6871bd0..669a2b77 100755 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,7 +2,7 @@ ### v0.37.23 -* Enhancement: support relative keyword for makefile extending to enable easy crate/workspace root extending #1175 +* Enhancement: support relative keyword for makefile extending to enable easy git/crate/workspace root extending #1175 * Maintenance: critical bug fix upgrade for duckscript ### v0.37.22 (2024-10-12) diff --git a/docs/_includes/content.md b/docs/_includes/content.md index 99b8de63..352ac455 100755 --- a/docs/_includes/content.md +++ b/docs/_includes/content.md @@ -1038,16 +1038,20 @@ extend = [ ] ``` -You can also change the relative path from the current makefile location to the crate root folder or workspace root folder by adding the relative keyword as follows: +You can also change the relative path from the current makefile location to the git root folder, crate root folder or workspace root folder by adding the relative keyword as follows: ```toml extend = { path = "./examples/python.toml", relative = "crate" } ``` Where relative can have the following values: + +* git - For nearest (up) .git folder location. * crate - For crate root (based on first Cargo.toml file) * workspace - For workspace root (based on second top Cargo.toml file) -Any other value defaults to the current makefile location. + +Any other value defaults to the current makefile location.
+Important to mention, all paths are relative from the currently parsed makefile. #### Automatically Extend Workspace Makefile diff --git a/examples/extends_list.toml b/examples/extends_list.toml index 0bb6b046..ce8fcdf3 100755 --- a/examples/extends_list.toml +++ b/examples/extends_list.toml @@ -3,7 +3,9 @@ extend = [ { path = "alias.toml" }, { path = "optional_makefile.toml", optional = true }, { path = "cwd.toml" }, + { path = "cwd.toml", relative = "bad" }, { path = "./examples/python.toml", relative = "crate" }, + { path = "./examples/javascript.toml", relative = "git" }, ] [config] diff --git a/src/lib/descriptor/mod.rs b/src/lib/descriptor/mod.rs index 08f05118..1dd292c1 100755 --- a/src/lib/descriptor/mod.rs +++ b/src/lib/descriptor/mod.rs @@ -32,6 +32,7 @@ use std::path::{Path, PathBuf}; #[derive(Debug)] enum RelativeTo { Makefile, + GitRoot, CrateRoot, WorkspaceRoot, } @@ -260,15 +261,22 @@ fn load_descriptor_extended_makefiles( } Extend::Options(extend_options) => { let force = !extend_options.optional.unwrap_or(false); - let relative_to = match extend_options + let relative_to_str = extend_options .relative .clone() - .unwrap_or("makefile".to_string()) - .as_str() - { + .unwrap_or("makefile".to_string()); + let relative_to = match relative_to_str.as_str() { + "git" => RelativeTo::GitRoot, "crate" => RelativeTo::CrateRoot, "workspace" => RelativeTo::WorkspaceRoot, - _ => RelativeTo::Makefile, + "makefile" => RelativeTo::Makefile, + _ => { + warn!( + "Unknown relative-to value: {}, defaulting to makefile", + &relative_to_str + ); + RelativeTo::Makefile + } }; load_external_descriptor(parent_path, &extend_options.path, force, false, relative_to) } @@ -329,6 +337,14 @@ fn load_external_descriptor( let descriptor_dir = match relative_to { RelativeTo::Makefile => base_path.to_string(), + RelativeTo::GitRoot => { + let git_root = environment::find_git_root(&PathBuf::from(base_path)); + debug!("git root: {:#?}", &git_root); + match git_root { + Some(git_root_dir) => git_root_dir.clone(), + None => base_path.to_string(), + } + } RelativeTo::CrateRoot => { let project_root = environment::get_project_root_for_path(&PathBuf::from(base_path)); debug!("project root: {:#?}", &project_root); diff --git a/src/lib/descriptor/mod_test.rs b/src/lib/descriptor/mod_test.rs index c6cafd07..efadf977 100755 --- a/src/lib/descriptor/mod_test.rs +++ b/src/lib/descriptor/mod_test.rs @@ -607,6 +607,50 @@ fn load_external_descriptor_extending_file_sub_folder() { assert_eq!(alias.unwrap(), "extended"); } +#[test] +#[ignore] +fn load_external_descriptor_simple_file_from_crate_root() { + let config = load_external_descriptor( + ".", + "./examples/alias.toml", + true, + false, + RelativeTo::CrateRoot, + ) + .unwrap(); + + assert!(config.config.is_none()); + assert!(config.env.is_none()); + assert!(config.tasks.is_some()); + + let tasks = config.tasks.unwrap(); + let test_task = tasks.get("D2").unwrap(); + let alias = test_task.alias.clone(); + assert_eq!(alias.unwrap(), "D"); +} + +#[test] +#[ignore] +fn load_external_descriptor_simple_file_from_git_root() { + let config = load_external_descriptor( + ".", + "./examples/alias.toml", + true, + false, + RelativeTo::GitRoot, + ) + .unwrap(); + + assert!(config.config.is_none()); + assert!(config.env.is_none()); + assert!(config.tasks.is_some()); + + let tasks = config.tasks.unwrap(); + let test_task = tasks.get("D2").unwrap(); + let alias = test_task.alias.clone(); + assert_eq!(alias.unwrap(), "D"); +} + #[test] #[ignore] fn load_external_descriptor_set_env() { diff --git a/src/lib/environment/mod.rs b/src/lib/environment/mod.rs index d296cfc4..814d8469 100644 --- a/src/lib/environment/mod.rs +++ b/src/lib/environment/mod.rs @@ -786,6 +786,31 @@ fn current_dir_or(fallback: &PathBuf) -> PathBuf { } } +pub(crate) fn find_git_root(directory: &PathBuf) -> Option { + let from_dir = if directory.to_str().unwrap_or(".") == "." { + current_dir_or(directory) + } else { + directory.to_path_buf() + }; + debug!("Looking for git root from directory: {:?}", &from_dir); + let file_path = Path::new(&from_dir).join(".git"); + + if file_path.exists() { + match from_dir.to_str() { + Some(directory_string) => Some(directory_string.to_string()), + _ => None, + } + } else { + match from_dir.parent() { + Some(parent_directory) => { + let parent_directory_path = parent_directory.to_path_buf(); + find_git_root(&parent_directory_path) + } + None => None, + } + } +} + pub(crate) fn get_project_root_for_path(directory: &PathBuf) -> Option { let from_dir = if directory.to_str().unwrap_or(".") == "." { current_dir_or(directory) diff --git a/src/lib/types.rs b/src/lib/types.rs index f4bb8cb6..9f4fe0a7 100755 --- a/src/lib/types.rs +++ b/src/lib/types.rs @@ -2072,8 +2072,8 @@ pub struct ExtendOptions { pub path: String, /// Enable optional extend (default to false) pub optional: Option, - /// Relative to option, sub as current makefile, crate root, workspace root, etc... - /// Possible values: (makefile, crate, workspace) + /// Relative to option, sub as current makefile, git root, crate root, workspace root, etc... + /// Possible values: (makefile, git, crate, workspace) pub relative: Option, }