release_kit/migrate/
git.rs1use std::process::{Command, Output};
9
10use camino::Utf8Path;
11
12use crate::diagnostic::{Diagnostic, Reason};
13use crate::error::RkError;
14
15pub fn run(target: &Utf8Path, args: &[&str]) -> Result<Output, RkError> {
21 let mut command = Command::new(crate::probes::git_bin());
22 for var in crate::maintenance::GIT_HOOK_VARS {
23 command.env_remove(var);
24 }
25 command
26 .env("LC_ALL", "C")
27 .env_remove("LANGUAGE")
28 .arg("-C")
29 .arg(target)
30 .args(args)
31 .output()
32 .map_err(|error| {
33 RkError::subprocess(
34 Diagnostic::new(
35 Reason::SubprocessSpawn,
36 format!("git could not be spawned: {error}"),
37 )
38 .expected("git on PATH, or RK_GIT_BIN naming it"),
39 )
40 })
41}
42
43pub fn stdout(target: &Utf8Path, args: &[&str]) -> Result<Vec<u8>, RkError> {
49 let out = run(target, args)?;
50 if !out.status.success() {
51 return Err(RkError::subprocess(
52 Diagnostic::new(
53 Reason::SubprocessFailed,
54 format!(
55 "git {} failed at {target}: {}",
56 args.join(" "),
57 String::from_utf8_lossy(&out.stderr).trim()
58 ),
59 )
60 .expected("a git repository with at least one commit"),
61 ));
62 }
63 Ok(out.stdout)
64}
65
66pub fn lines(target: &Utf8Path, args: &[&str]) -> Result<Vec<String>, RkError> {
72 Ok(String::from_utf8_lossy(&stdout(target, args)?)
73 .lines()
74 .filter(|line| !line.is_empty())
75 .map(str::to_owned)
76 .collect())
77}
78
79pub fn regular_blobs(
86 target: &Utf8Path,
87 rev: &str,
88 paths: &[&str],
89) -> Result<std::collections::BTreeMap<String, String>, RkError> {
90 let mut args = vec!["ls-tree", "-r", "-z", rev, "--"];
91 args.extend_from_slice(paths);
92 Ok(stdout(target, &args)?
93 .split(|byte| *byte == 0)
94 .filter_map(|record| {
95 let (meta, path) = std::str::from_utf8(record).ok()?.split_once('\t')?;
96 let mut fields = meta.split(' ');
97 let mode = fields.next()?;
98 let oid = fields.nth(1)?;
99 matches!(mode, "100644" | "100755").then(|| (path.to_owned(), oid.to_owned()))
100 })
101 .collect())
102}
103
104pub fn raw_blob_ids(target: &Utf8Path, paths: &[&str]) -> Result<Vec<String>, RkError> {
111 let mut args = vec!["hash-object", "--no-filters", "--"];
112 args.extend_from_slice(paths);
113 lines(target, &args)
114}