|
| 1 | +diff --git a/src/app/screens/details_actions.rs b/src/app/screens/details_actions.rs |
| 2 | +index 77e85cf..3eae052 100644 |
| 3 | +--- a/src/app/screens/details_actions.rs |
| 4 | ++++ b/src/app/screens/details_actions.rs |
| 5 | +@@ -1,4 +1,4 @@ |
| 6 | +-use crate::app::{config::Config, logging::Logger}; |
| 7 | ++use crate::app::config::Config; |
| 8 | + |
| 9 | + use super::CurrentScreen; |
| 10 | + use ::patch_hub::lore::{lore_api_client::BlockingLoreAPIClient, lore_session, patch::Patch}; |
| 11 | +@@ -206,80 +206,151 @@ impl DetailsActions { |
| 12 | + Ok(()) |
| 13 | + } |
| 14 | + |
| 15 | +- /// Apply the patchset to the current selected kernel tree |
| 16 | +- pub fn apply_patchset(&self, config: &Config) { |
| 17 | +- let tree = config.current_tree().as_ref().unwrap(); |
| 18 | +- let tree_path = config.kernel_tree_path(tree).unwrap(); |
| 19 | +- let am_options = config.git_am_options(); |
| 20 | +- let branch_prefix = config.git_am_branch_prefix(); |
| 21 | +- // TODO: Select a kernel tree |
| 22 | +- |
| 23 | +- // Change the current working directory to the tree_path |
| 24 | +- // Save the old working directory |
| 25 | +- let oldwd = std::env::current_dir().unwrap(); |
| 26 | +- |
| 27 | +- std::env::set_current_dir(tree_path).unwrap(); |
| 28 | +- // TODO: Select a branch |
| 29 | +- // 3. Create a new branch |
| 30 | +- let branch_name = format!( |
| 31 | ++ /// Try to apply the patchset to a target kernel tree and returns a `String` |
| 32 | ++ /// informing if the apply succeeded or failed and why. |
| 33 | ++ pub fn apply_patchset(&self, config: &Config) -> String { |
| 34 | ++ // 1. Check if target kernel tree is set |
| 35 | ++ let kernel_tree_id = if let Some(target) = config.target_kernel_tree() { |
| 36 | ++ target |
| 37 | ++ } else { |
| 38 | ++ return "[error] target kernel tree unset".to_string(); |
| 39 | ++ }; |
| 40 | ++ |
| 41 | ++ // 2. Check if target kernel tree exists |
| 42 | ++ let kernel_tree = if let Some(tree) = config.get_kernel_tree(kernel_tree_id) { |
| 43 | ++ tree |
| 44 | ++ } else { |
| 45 | ++ return format!("[error] invalid target kernel tree '{}'", kernel_tree_id); |
| 46 | ++ }; |
| 47 | ++ |
| 48 | ++ // 3. Check if path to kernel tree is valid |
| 49 | ++ let kernel_tree_path = Path::new(kernel_tree.path()); |
| 50 | ++ if !kernel_tree_path.is_dir() { |
| 51 | ++ return format!("[error] {} isn't a directory", kernel_tree.path()); |
| 52 | ++ } else if !kernel_tree_path.join(".git").is_dir() { |
| 53 | ++ return format!("[error] {} isn't a git repository", kernel_tree.path()); |
| 54 | ++ } |
| 55 | ++ |
| 56 | ++ // 4. Check if there are any `git rebase`, `git merge`, `git bisect`, or |
| 57 | ++ // `git am` already happening |
| 58 | ++ if kernel_tree_path.join(".git/rebase-merge").is_dir() { |
| 59 | ++ return "[error] rebase in progress. \nrun `git rebase --abort` before continuing" |
| 60 | ++ .to_string(); |
| 61 | ++ } else if kernel_tree_path.join(".git/MERGE_HEAD").is_file() { |
| 62 | ++ return "[error] merge in progress. \nrun `git rebase --abort` before continuing" |
| 63 | ++ .to_string(); |
| 64 | ++ } else if kernel_tree_path.join(".git/BISECT_LOG").is_file() { |
| 65 | ++ return "[error] bisect in progress. \nrun `git bisect reset` before continuing" |
| 66 | ++ .to_string(); |
| 67 | ++ } else if kernel_tree_path.join(".git/rebase-apply").is_dir() { |
| 68 | ++ return "[error] `git am` already in progress. \nrun `git am --abort` before continuing".to_string(); |
| 69 | ++ } |
| 70 | ++ |
| 71 | ++ // 5. Check if there are any staged or unstaged changes |
| 72 | ++ let git_status_out = Command::new("git") |
| 73 | ++ .arg("-C") |
| 74 | ++ .arg(kernel_tree.path()) |
| 75 | ++ .arg("status") |
| 76 | ++ .arg("--porcelain") |
| 77 | ++ .output() |
| 78 | ++ .unwrap(); |
| 79 | ++ let git_status_out = String::from_utf8_lossy(&git_status_out.stdout); |
| 80 | ++ if !git_status_out.is_empty() { |
| 81 | ++ return format!( |
| 82 | ++ "[error] there are staged and/or unstaged changes\n{}", |
| 83 | ++ git_status_out |
| 84 | ++ ); |
| 85 | ++ } |
| 86 | ++ |
| 87 | ++ // 6. Check if base branch is valid |
| 88 | ++ let git_show_ref_out = Command::new("git") |
| 89 | ++ .arg("-C") |
| 90 | ++ .arg(kernel_tree.path()) |
| 91 | ++ .arg("show-ref") |
| 92 | ++ .arg("--verify") |
| 93 | ++ .arg("--quiet") |
| 94 | ++ .arg(format!("refs/heads/{}", kernel_tree.branch())) |
| 95 | ++ .output() |
| 96 | ++ .unwrap(); |
| 97 | ++ if !git_show_ref_out.status.success() { |
| 98 | ++ return format!( |
| 99 | ++ "[error] invalid branch '{}' for '{}'", |
| 100 | ++ kernel_tree.branch(), |
| 101 | ++ kernel_tree.path() |
| 102 | ++ ); |
| 103 | ++ } |
| 104 | ++ |
| 105 | ++ // 7. Save original branch, switch to base branch, and checkout to target |
| 106 | ++ // branch |
| 107 | ++ let original_branch = Command::new("git") |
| 108 | ++ .arg("-C") |
| 109 | ++ .arg(kernel_tree.path()) |
| 110 | ++ .arg("rev-parse") |
| 111 | ++ .arg("--abbrev-ref") |
| 112 | ++ .arg("HEAD") |
| 113 | ++ .output() |
| 114 | ++ .unwrap(); |
| 115 | ++ let mut original_branch = String::from_utf8_lossy(&original_branch.stdout).to_string(); |
| 116 | ++ original_branch.pop(); |
| 117 | ++ let _ = Command::new("git") |
| 118 | ++ .arg("-C") |
| 119 | ++ .arg(kernel_tree.path()) |
| 120 | ++ .arg("switch") |
| 121 | ++ .arg(kernel_tree.branch()) |
| 122 | ++ .output() |
| 123 | ++ .unwrap(); |
| 124 | ++ let target_branch_name = format!( |
| 125 | + "{}{}", |
| 126 | +- branch_prefix, |
| 127 | ++ config.git_am_branch_prefix(), |
| 128 | + chrono::Utc::now().format("%Y-%m-%d-%H-%M-%S") |
| 129 | + ); |
| 130 | + let _ = Command::new("git") |
| 131 | ++ .arg("-C") |
| 132 | ++ .arg(kernel_tree.path()) |
| 133 | + .arg("checkout") |
| 134 | + .arg("-b") |
| 135 | +- .arg(&branch_name) |
| 136 | ++ .arg(&target_branch_name) |
| 137 | + .output() |
| 138 | + .unwrap(); |
| 139 | + |
| 140 | +- // 3. Apply the patchset |
| 141 | +- let mut cmd = Command::new("git"); |
| 142 | +- |
| 143 | +- cmd.arg("am").arg(&self.path); |
| 144 | +- |
| 145 | +- am_options.split_whitespace().for_each(|opt| { |
| 146 | +- cmd.arg(opt); |
| 147 | ++ // 8. Apply the patchset |
| 148 | ++ let mut git_am_out = Command::new("git"); |
| 149 | ++ git_am_out |
| 150 | ++ .arg("-C") |
| 151 | ++ .arg(kernel_tree.path()) |
| 152 | ++ .arg("am") |
| 153 | ++ .arg(&self.patchset_path); |
| 154 | ++ config.git_am_options().split_whitespace().for_each(|opt| { |
| 155 | ++ git_am_out.arg(opt); |
| 156 | + }); |
| 157 | +- |
| 158 | +- let out = cmd.output().unwrap(); |
| 159 | +- |
| 160 | +- if !out.status.success() { |
| 161 | +- Logger::error(format!( |
| 162 | +- "Failed to apply the patchset `{}`", |
| 163 | +- self.representative_patch.title() |
| 164 | +- )); |
| 165 | +- Logger::error(String::from_utf8_lossy(&out.stderr)); |
| 166 | ++ let git_am_out = git_am_out.output().unwrap(); |
| 167 | ++ if !git_am_out.status.success() { |
| 168 | + let _ = Command::new("git") |
| 169 | ++ .arg("-C") |
| 170 | ++ .arg(kernel_tree.path()) |
| 171 | + .arg("am") |
| 172 | + .arg("--abort") |
| 173 | + .output() |
| 174 | + .unwrap(); |
| 175 | +- } else { |
| 176 | +- Logger::info(format!( |
| 177 | +- "Patchset `{}` applied successfully to `{}` tree at branch `{}`", |
| 178 | +- self.representative_patch.title(), |
| 179 | +- tree, |
| 180 | +- branch_name |
| 181 | +- )); |
| 182 | + } |
| 183 | + |
| 184 | +- // 4. git checkout - |
| 185 | ++ // 9. Return back to original branch |
| 186 | + let _ = Command::new("git") |
| 187 | +- .arg("checkout") |
| 188 | +- .arg("-") |
| 189 | ++ .arg("-C") |
| 190 | ++ .arg(kernel_tree.path()) |
| 191 | ++ .arg("switch") |
| 192 | ++ .arg(&original_branch) |
| 193 | + .output() |
| 194 | + .unwrap(); |
| 195 | + |
| 196 | +- if !out.status.success() { |
| 197 | +- let _ = Command::new("git") |
| 198 | +- .arg("branch") |
| 199 | +- .arg("-D") |
| 200 | +- .arg(&branch_name) |
| 201 | +- .output() |
| 202 | +- .unwrap(); |
| 203 | ++ if git_am_out.status.success() { |
| 204 | ++ format!("[success] patchset '{}' applied successfully to '{}' tree in branch '{}' (based on '{}' branch)", self.representative_patch.title(), kernel_tree.path(), &target_branch_name, kernel_tree.branch()) |
| 205 | ++ } else { |
| 206 | ++ format!( |
| 207 | ++ "[error] `git am` failed\n{}{}", |
| 208 | ++ &original_branch, |
| 209 | ++ String::from_utf8_lossy(&git_am_out.stderr) |
| 210 | ++ ) |
| 211 | + } |
| 212 | +- // 5. CD back |
| 213 | +- std::env::set_current_dir(&oldwd).unwrap(); |
| 214 | + } |
| 215 | + } |
0 commit comments