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..0d56ab0 100644 --- a/src/app/screens/details_actions.rs +++ b/src/app/screens/details_actions.rs @@ -231,18 +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<'a>(&self, config: &'a Config) -> Result<&'a KernelTree, String> { - let kernel_tree_id = if let Some(target) = config.target_kernel_tree() { - target + /// 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 { - return Err("target kernel tree unset".to_string()); - }; + let kernel_tree_path = self.get_current_kernel_tree()?; + 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(), + kernel_tree.clone(), + ); + config + .save_patch_hub_config() + .map_err(|e| format!("failed to save config: {e}"))?; - let kernel_tree = if let Some(tree) = config.get_kernel_tree(kernel_tree_id) { - tree - } else { - return Err(format!("invalid target kernel tree '{kernel_tree_id}'")); + (kernel_tree, true) }; let kernel_tree_path = Path::new(kernel_tree.path()); @@ -252,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, @@ -318,6 +335,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,19 +478,23 @@ 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 { - let kernel_tree = self.validate_kernel_tree(config)?; - self.check_git_state(kernel_tree)?; + pub fn apply_patchset(&self, config: &mut Config) -> Result { + 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)?; - 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(_) => { - 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)) }