From 88fe730897fd8221e5573ebba56ee7b705697640 Mon Sep 17 00:00:00 2001 From: Pedro Yudi Honda Date: Wed, 8 Jul 2026 15:39:13 -0300 Subject: [PATCH 1/2] feat: implements auto-tree detector Implements first version of auto tree detector, that does everything silently. When applying a patch, if no tree is targeted, it checks if the currenr working directory is a valid branch and targets it. Signed-off-by: Pedro Yudi Honda --- src/app/config/mod.rs | 14 ++++++ src/app/mod.rs | 2 +- src/app/screens/details_actions.rs | 68 +++++++++++++++++++++++++----- 3 files changed, 72 insertions(+), 12 deletions(-) diff --git a/src/app/config/mod.rs b/src/app/config/mod.rs index 18766c4..f4ca855 100644 --- a/src/app/config/mod.rs +++ b/src/app/config/mod.rs @@ -57,6 +57,12 @@ pub struct KernelTree { branch: String, } +impl KernelTree { + pub fn new(path: String, branch: String) -> Self { + Self { path, branch } + } +} + impl Default for Config { fn default() -> Self { let home = env::var("HOME").unwrap_or_else(|_| { @@ -151,6 +157,10 @@ impl Config { self.page_size } + pub fn add_kernel_tree(&mut self, id: String, kernel_tree: KernelTree) { + self.kernel_trees.insert(id, kernel_tree); + } + pub fn set_page_size(&mut self, page_size: usize) { self.page_size = page_size; } @@ -176,6 +186,10 @@ impl Config { self.git_am_options = git_am_options; } + pub fn set_target_kernel_tree(&mut self, kernel_tree_id: Option) { + self.target_kernel_tree = kernel_tree_id; + } + #[allow(dead_code)] /// Returns the list of names of the registered kernel trees pub fn kernel_trees(&self) -> HashSet<&String> { diff --git a/src/app/mod.rs b/src/app/mod.rs index 555362f..248d1f2 100644 --- a/src/app/mod.rs +++ b/src/app/mod.rs @@ -337,7 +337,7 @@ impl App { .details_actions .as_ref() .unwrap() - .apply_patchset(&self.config) + .apply_patchset(&mut self.config) { Ok(msg) => InfoPopUp::generate_info_popup("Patchset Apply Success", &msg), Err(msg) => InfoPopUp::generate_info_popup("Patchset Apply Fail", &msg), diff --git a/src/app/screens/details_actions.rs b/src/app/screens/details_actions.rs index a3807cd..72ec0ce 100644 --- a/src/app/screens/details_actions.rs +++ b/src/app/screens/details_actions.rs @@ -232,15 +232,35 @@ impl DetailsActions { /// that kernel tree is a valid git directory. /// /// Returns the a valid `KernelTree` or a `String` with the error message on failure. - fn validate_kernel_tree<'a>(&self, config: &'a Config) -> Result<&'a KernelTree, String> { + fn validate_kernel_tree(&self, config: &mut Config) -> Result { let kernel_tree_id = if let Some(target) = config.target_kernel_tree() { - target + target.clone() } else { - return Err("target kernel tree unset".to_string()); + let kernel_tree_path = self.get_current_kernel_tree()?; + let kernel_tree_id = kernel_tree_path + .split('/') + .last() + .unwrap_or("default") + .to_string(); + let current_branch = self.get_current_branch(&KernelTree::new( + kernel_tree_path.clone(), + "".to_string(), + ))?; + + config.set_target_kernel_tree(Some(kernel_tree_id.clone())); + config.add_kernel_tree( + kernel_tree_id.clone(), + KernelTree::new(kernel_tree_path, current_branch), + ); + config + .save_patch_hub_config() + .map_err(|e| format!("failed to save config: {e}"))?; + + config.target_kernel_tree().as_ref().unwrap().clone() }; - let kernel_tree = if let Some(tree) = config.get_kernel_tree(kernel_tree_id) { - tree + let kernel_tree = if let Some(tree) = config.get_kernel_tree(&kernel_tree_id) { + tree.clone() } else { return Err(format!("invalid target kernel tree '{kernel_tree_id}'")); }; @@ -318,6 +338,32 @@ impl DetailsActions { Ok(()) } + /// Get the current kernel tree + /// + /// Returns the kernel tree path as a `String` or a `String` with the error message on failure + fn get_current_kernel_tree(&self) -> Result { + if Command::new("make") + .args(["-s", "kernelversion"]) + .output() + .map_err(|_| "failed to get current kernel tree state".to_string())? + .status + .success() + { + let output = Command::new("git") + .args(["rev-parse", "--show-toplevel"]) + .output() + .map_err(|_| "failed to get current kernel tree path".to_string())?; + + if output.status.success() { + Ok(String::from_utf8_lossy(&output.stdout).trim().to_owned()) + } else { + Err("not in a valid kernel tree".to_string()) + } + } else { + Err("not in a valid kernel tree".to_string()) + } + } + /// Get the current branch of the supplied kernel tree /// /// Returns the branch name as a `String` or a `String` with the error message on failure @@ -435,15 +481,15 @@ impl DetailsActions { /// Returns a `Result` containing either the success or the error message. /// # TODO: /// - Add unit tests - pub fn apply_patchset(&self, config: &Config) -> Result { + pub fn apply_patchset(&self, config: &mut Config) -> Result { let kernel_tree = self.validate_kernel_tree(config)?; - self.check_git_state(kernel_tree)?; + self.check_git_state(&kernel_tree)?; - let original_branch = self.get_current_branch(kernel_tree)?; - let target_branch = self.create_target_branch(kernel_tree, config)?; + let original_branch = self.get_current_branch(&kernel_tree)?; + let target_branch = self.create_target_branch(&kernel_tree, config)?; - let git_am_result = self.run_git_am(kernel_tree, config); - self.switch_to_branch(kernel_tree, &original_branch)?; + let git_am_result = self.run_git_am(&kernel_tree, config); + self.switch_to_branch(&kernel_tree, &original_branch)?; match git_am_result { Ok(_) => { From f66bb83c07e80b5e32a64e455ec357f344a07dc3 Mon Sep 17 00:00:00 2001 From: Pedro Yudi Honda Date: Tue, 28 Jul 2026 19:39:15 -0300 Subject: [PATCH 2/2] feat: adds message to auto-tree detector Changes message to mention the tree was auto detected when it is the case. This way, there is at least some warning to when the system triggers. Signed-off-by: Pedro Yudi Honda --- src/app/screens/details_actions.rs | 47 +++++++++++++++--------------- 1 file changed, 24 insertions(+), 23 deletions(-) diff --git a/src/app/screens/details_actions.rs b/src/app/screens/details_actions.rs index 72ec0ce..0d56ab0 100644 --- a/src/app/screens/details_actions.rs +++ b/src/app/screens/details_actions.rs @@ -231,38 +231,35 @@ impl DetailsActions { /// Checks if there is a `target_kernel_tree` and if it is in `Config::kernel_trees` and if /// that kernel tree is a valid git directory. /// - /// Returns the a valid `KernelTree` or a `String` with the error message on failure. - fn validate_kernel_tree(&self, config: &mut Config) -> Result { - let kernel_tree_id = if let Some(target) = config.target_kernel_tree() { - target.clone() + /// Returns the a valid `KernelTree` and whether it was auto-detected. + fn validate_kernel_tree(&self, config: &mut Config) -> Result<(KernelTree, bool), String> { + let (kernel_tree, is_autodetected) = if let Some(target) = config.target_kernel_tree() { + (config.get_kernel_tree(target) + .ok_or_else(|| format!("invalid target kernel tree '{target}'"))?.clone(), false) } else { let kernel_tree_path = self.get_current_kernel_tree()?; - let kernel_tree_id = kernel_tree_path - .split('/') - .last() - .unwrap_or("default") - .to_string(); let current_branch = self.get_current_branch(&KernelTree::new( kernel_tree_path.clone(), "".to_string(), ))?; + let kernel_tree = KernelTree::new(kernel_tree_path, current_branch); + + let kernel_tree_id = kernel_tree.path() + .split('/') + .last() + .unwrap_or("default") + .to_string(); config.set_target_kernel_tree(Some(kernel_tree_id.clone())); config.add_kernel_tree( - kernel_tree_id.clone(), - KernelTree::new(kernel_tree_path, current_branch), + kernel_tree_id.clone(), + kernel_tree.clone(), ); config - .save_patch_hub_config() - .map_err(|e| format!("failed to save config: {e}"))?; + .save_patch_hub_config() + .map_err(|e| format!("failed to save config: {e}"))?; - config.target_kernel_tree().as_ref().unwrap().clone() - }; - - let kernel_tree = if let Some(tree) = config.get_kernel_tree(&kernel_tree_id) { - tree.clone() - } else { - return Err(format!("invalid target kernel tree '{kernel_tree_id}'")); + (kernel_tree, true) }; let kernel_tree_path = Path::new(kernel_tree.path()); @@ -272,7 +269,7 @@ impl DetailsActions { return Err(format!("{} isn't a git repository", kernel_tree.path())); } - Ok(kernel_tree) + Ok((kernel_tree, is_autodetected)) } // Ensures the kernel directory is not currently in another git operation, @@ -482,7 +479,7 @@ impl DetailsActions { /// # TODO: /// - Add unit tests pub fn apply_patchset(&self, config: &mut Config) -> Result { - let kernel_tree = self.validate_kernel_tree(config)?; + let (kernel_tree, is_autodetected) = self.validate_kernel_tree(config)?; self.check_git_state(&kernel_tree)?; let original_branch = self.get_current_branch(&kernel_tree)?; @@ -493,7 +490,11 @@ impl DetailsActions { match git_am_result { Ok(_) => { - Ok(format!(" Patchset '{}' applied successfully!\n\n - Kernel Tree: '{}'\n\n - Base Branch: '{}'\n\n - Applied branch: '{}'", self.representative_patch.title(), kernel_tree.path(), kernel_tree.branch(), &target_branch)) + Ok(format!(" Patchset '{}' applied successfully!\n\n - Kernel Tree: '{}'{}\n\n - Base Branch: '{}'{}\n\n - Applied branch: '{}'", + self.representative_patch.title(), + kernel_tree.path(), if is_autodetected { " (auto-detected)" } else { "" }, + kernel_tree.branch(), if is_autodetected { " (auto-detected)" } else { "" }, + &target_branch)) }, Err(e) => Err(format!( "`git am` failed\n{}{}", &original_branch, e)) }