@@ -8,34 +8,53 @@ pub async fn get_messages(working_directory: &Path, shas: &[Oid]) -> Result<Hash
return Ok(HashMap::default());
}
- const MARKER: &str = "<MARKER>";
+ let output = if cfg!(windows) {
+ // Windows has a maximum invocable command length, so we chunk the input.
+ // Actual max is 32767, but we leave some room for the rest of the command as we aren't in precise control of what std might do here
+ const MAX_CMD_LENGTH: usize = 30000;
+ // 40 bytes of hash, 2 quotes and a separating space
+ const SHA_LENGTH: usize = 40 + 2 + 1;
+ const MAX_ENTRIES_PER_INVOCATION: usize = MAX_CMD_LENGTH / SHA_LENGTH;
+
+ let mut result = vec![];
+ for shas in shas.chunks(MAX_ENTRIES_PER_INVOCATION) {
+ let partial = get_messages_impl(working_directory, shas).await?;
+ result.extend(partial);
+ }
+ result
+ } else {
+ get_messages_impl(working_directory, shas).await?
+ };
+
+ Ok(shas
+ .iter()
+ .cloned()
+ .zip(output)
+ .collect::<HashMap<Oid, String>>())
+}
- let output = util::command::new_smol_command("git")
- .current_dir(working_directory)
+async fn get_messages_impl(working_directory: &Path, shas: &[Oid]) -> Result<Vec<String>> {
+ const MARKER: &str = "<MARKER>";
+ let mut cmd = util::command::new_smol_command("git");
+ cmd.current_dir(working_directory)
.arg("show")
.arg("-s")
.arg(format!("--format=%B{}", MARKER))
- .args(shas.iter().map(ToString::to_string))
+ .args(shas.iter().map(ToString::to_string));
+ let output = cmd
.output()
.await
- .context("starting git blame process")?;
-
+ .with_context(|| format!("starting git blame process: {:?}", cmd))?;
anyhow::ensure!(
output.status.success(),
"'git show' failed with error {:?}",
output.status
);
-
- Ok(shas
- .iter()
- .cloned()
- .zip(
- String::from_utf8_lossy(&output.stdout)
- .trim()
- .split_terminator(MARKER)
- .map(|str| str.trim().replace("<", "<").replace(">", ">")),
- )
- .collect::<HashMap<Oid, String>>())
+ Ok(String::from_utf8_lossy(&output.stdout)
+ .trim()
+ .split_terminator(MARKER)
+ .map(|str| str.trim().replace("<", "<").replace(">", ">"))
+ .collect::<Vec<_>>())
}
/// Parse the output of `git diff --name-status -z`