Allow to interdiff with a pre-made ref

This commit is contained in:
Quentin Boyer 2025-01-14 14:31:48 +01:00
parent 2fc6af4390
commit e9a3c9a6b0

View file

@ -238,6 +238,13 @@ struct FormatPatch {
help = "Reference for the interdiff (defaults to ${config.interdiff_base})" help = "Reference for the interdiff (defaults to ${config.interdiff_base})"
)] )]
base_diff: Option<String>, base_diff: Option<String>,
#[arg(
short = 'D',
long,
help = "Perform the interdiff with an explicit reference",
conflicts_with = "diff"
)]
diff_to: Option<String>,
extra_args: Vec<String>, extra_args: Vec<String>,
} }
@ -345,102 +352,107 @@ impl FormatPatch {
}) })
}; };
let _version_dir = if let Some(interdiff) = self.diff { let _version_dir = match (self.diff, self.diff_to) {
let base = self (None, None) => format_patch(&[])?,
.base_diff (Some(_), Some(_)) => unreachable!(),
.or(config.interdiff_base) (Some(patch_version), None) => {
.unwrap_or_else(|| String::from("origin/master")); let base = self
.base_diff
.or(config.interdiff_base)
.unwrap_or_else(|| String::from("origin/master"));
struct TempBranch<'a> { struct TempBranch<'a> {
name: &'a str, name: &'a str,
git: &'a dyn Fn(&[&str]) -> Result<String>, git: &'a dyn Fn(&[&str]) -> Result<String>,
}
impl<'a> Drop for TempBranch<'a> {
fn drop(&mut self) {
(self.git)(&["branch", "-D", self.name]).unwrap();
} }
}
let branch = { impl<'a> Drop for TempBranch<'a> {
let name = "__patch_old"; fn drop(&mut self) {
git_cd(&["branch", name, &base])?; (self.git)(&["branch", "-D", self.name]).unwrap();
TempBranch { name, git: &git_cd } }
};
struct GitWorktree {
_dir: TempDir,
path: String,
}
impl GitWorktree {
pub fn exec(&self, args: &[&str]) -> Result<String> {
let mut a = vec!["-C", &self.path];
a.extend_from_slice(args);
git_bare(a)
} }
}
impl Drop for GitWorktree { let branch = {
fn drop(&mut self) { let name = "__patch_old";
self.exec(&["worktree", "remove", "--force", &self.path]) git_cd(&["branch", name, &base])?;
.unwrap(); TempBranch { name, git: &git_cd }
};
struct GitWorktree {
_dir: TempDir,
path: String,
} }
}
let wt = { impl GitWorktree {
let worktree = temp_dir::TempDir::new() pub fn exec(&self, args: &[&str]) -> Result<String> {
.into_diagnostic() let mut a = vec!["-C", &self.path];
.wrap_err("Could not create worktree directory")?; a.extend_from_slice(args);
let worktree_path = worktree git_bare(a)
.path() }
.to_str()
.ok_or(miette!("Temp dir is not utf-8"))?
.to_string();
git_cd(&["worktree", "add", "--detach", &worktree_path])?;
GitWorktree {
path: worktree_path,
_dir: worktree,
} }
};
wt.exec(&["switch", branch.name])?; impl Drop for GitWorktree {
fn drop(&mut self) {
self.exec(&["worktree", "remove", "--force", &self.path])
.unwrap();
}
}
let patches = branch_dir let wt = {
.join(&interdiff.to_string()) let worktree = temp_dir::TempDir::new()
.read_dir()
.into_diagnostic()
.wrap_err("Could not read interdiff folder")?
.map(|e| -> Result<_> {
let e = e
.into_diagnostic() .into_diagnostic()
.wrap_err("Could not read interdiff entry")?; .wrap_err("Could not create worktree directory")?;
let path = e let worktree_path = worktree
.path() .path()
.to_str() .to_str()
.ok_or(miette!("Interdiff patch path is not utf-8"))? .ok_or(miette!("Temp dir is not utf-8"))?
.to_string(); .to_string();
match path.contains("cover-letter") { git_cd(&["worktree", "add", "--detach", &worktree_path])?;
true => Ok(None),
false => Ok(Some(path)),
}
})
.filter_map(|e| e.transpose())
.collect::<Result<Vec<_>>>()?;
let mut apply_args = vec!["am", "-3"];
apply_args.extend(patches.iter().map(|s| s.deref()));
wt.exec(&apply_args)?;
let interdiff_branch = format!("--interdiff={}", branch.name); GitWorktree {
format_patch(&[&interdiff_branch])? path: worktree_path,
} else { _dir: worktree,
format_patch(&[])? }
};
wt.exec(&["switch", branch.name])?;
let patches = branch_dir
.join(&patch_version.to_string())
.read_dir()
.into_diagnostic()
.wrap_err("Could not read interdiff folder")?
.map(|e| -> Result<_> {
let e = e
.into_diagnostic()
.wrap_err("Could not read interdiff entry")?;
let path = e
.path()
.to_str()
.ok_or(miette!("Interdiff patch path is not utf-8"))?
.to_string();
match path.contains("cover-letter") {
true => Ok(None),
false => Ok(Some(path)),
}
})
.filter_map(|e| e.transpose())
.collect::<Result<Vec<_>>>()?;
let mut apply_args = vec!["am", "-3"];
apply_args.extend(patches.iter().map(|s| s.deref()));
wt.exec(&apply_args)?;
let interdiff_branch = format!("--interdiff={}", branch.name);
format_patch(&[&interdiff_branch])?
}
(None, Some(diff_to)) => {
format_patch(&[&format!("--interdiff={diff_to}")])?
},
}; };
let cover_letter = branch_dir.join(COVER_LETTER_NAME); let cover_letter = branch_dir.join(COVER_LETTER_NAME);