git_policy_cli/
service_native.rs1use super::capture_invocation::InvocationCapture;
18use super::commit_args::{resolve_private_commit_args, split_commit_invocation, without_all_flag};
19use super::commit_preparation::{PreparationRequest, read_prepared_commit, run_native_commit};
20use super::commit_transaction::TransactionStop;
21use super::global_arguments::global_layout;
22use super::shadow_create::create_shadow_repository_at;
23use super::transaction_git::GitContext;
24use super::transaction_journal::TransactionMode;
25use std::ffi::OsString;
26use std::path::Path;
27
28#[derive(Clone, Debug, Eq, PartialEq)]
30pub struct GitBuilt {
31 pub commit: String,
33 pub parents: Vec<String>,
35 pub message: String,
37}
38
39pub fn message_of(raw: &[u8]) -> String {
41 let start: usize = raw.windows(2).position(|window| { return window == b"\n\n"; }).map_or(raw.len(), |at| { return at + 2; });
42 return String::from_utf8_lossy(&raw[start..]).into_owned();
43}
44
45pub struct BuildInput<'a> {
47 pub context: &'a GitContext,
49 pub cwd: &'a Path,
51 pub capture: &'a InvocationCapture,
53 pub scratch: &'a Path,
55 pub commit_index: &'a Path,
57 pub arguments: &'a [OsString],
59 pub pathspecs: &'a [String],
61 pub mode: TransactionMode,
63 pub staged_all: bool,
65 pub selected_privately: bool,
68 pub quiet: bool,
70}
71
72pub fn parents_of(raw: &[u8]) -> Vec<String> {
74 let header_end: usize = raw.windows(2).position(|window| { return window == b"\n\n"; }).unwrap_or(raw.len());
75 return String::from_utf8_lossy(&raw[..header_end])
76 .lines()
77 .filter_map(|line| { return line.strip_prefix("parent ").map(str::to_string); })
78 .collect();
79}
80
81pub fn private_invocation(
92 arguments: &[OsString],
93 pathspecs: &[String],
94 mode: TransactionMode,
95 staged_all: bool,
96 selected_privately: bool,
97) -> (Vec<String>, Vec<String>) {
98 let text: Vec<String> = arguments.iter().map(|token| { return token.to_string_lossy().into_owned(); }).collect();
99 let private_args: Vec<String> = resolve_private_commit_args(text.as_slice(), pathspecs, mode, selected_privately);
100 let owned: Vec<OsString> = private_args.iter().map(OsString::from).collect();
101 let index: usize = global_layout(owned.as_slice()).prefix_len;
102 let (globals, commit_args): (Vec<String>, Vec<String>) = split_commit_invocation(private_args.as_slice(), index);
103 return if staged_all { (globals, without_all_flag(commit_args.as_slice())) } else { (globals, commit_args) };
104}
105
106pub fn build_with_git(input: &BuildInput<'_>) -> Result<GitBuilt, TransactionStop> {
122 let shadow = input.scratch.join("shadow");
123 create_shadow_repository_at(input.context, input.cwd, input.capture, shadow.as_path(), input.scratch)?;
124 let (globals, mut commit_args): (Vec<String>, Vec<String>) = private_invocation(input.arguments, input.pathspecs, input.mode, input.staged_all, input.selected_privately);
125 if input.quiet {
126 commit_args.push(String::from("--quiet"));
127 }
128 let request: PreparationRequest<'_> = PreparationRequest {
129 capture: input.capture,
130 shadow: shadow.as_path(),
131 commit_index: input.commit_index,
132 global_args: globals.as_slice(),
133 commit_args: commit_args.as_slice(),
134 object_directory: Some(input.capture.layout.object_directory.as_path()),
135 };
136 let status: i32 = run_native_commit(input.context, input.cwd, &request).map_err(|error| { return TransactionStop::Message(error.to_string()); })?;
137 if status != 0 {
138 return Err(TransactionStop::NativeExit(status));
139 }
140 let prepared = read_prepared_commit(input.context, shadow.as_path())?;
141 return Ok(GitBuilt { parents: parents_of(prepared.raw.as_slice()), message: message_of(prepared.raw.as_slice()), commit: prepared.oid });
142}
143
144#[cfg(test)]
146#[path = "service_native_tests.rs"]
147mod tests;