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 quiet: bool,
67}
68
69pub fn parents_of(raw: &[u8]) -> Vec<String> {
71 let header_end: usize = raw.windows(2).position(|window| { return window == b"\n\n"; }).unwrap_or(raw.len());
72 return String::from_utf8_lossy(&raw[..header_end])
73 .lines()
74 .filter_map(|line| { return line.strip_prefix("parent ").map(str::to_string); })
75 .collect();
76}
77
78pub fn private_invocation(arguments: &[OsString], pathspecs: &[String], mode: TransactionMode, staged_all: bool) -> (Vec<String>, Vec<String>) {
89 let text: Vec<String> = arguments.iter().map(|token| { return token.to_string_lossy().into_owned(); }).collect();
90 let private_args: Vec<String> = resolve_private_commit_args(text.as_slice(), pathspecs, mode, false);
91 let owned: Vec<OsString> = private_args.iter().map(OsString::from).collect();
92 let index: usize = global_layout(owned.as_slice()).prefix_len;
93 let (globals, commit_args): (Vec<String>, Vec<String>) = split_commit_invocation(private_args.as_slice(), index);
94 return if staged_all { (globals, without_all_flag(commit_args.as_slice())) } else { (globals, commit_args) };
95}
96
97pub fn build_with_git(input: &BuildInput<'_>) -> Result<GitBuilt, TransactionStop> {
113 let shadow = input.scratch.join("shadow");
114 create_shadow_repository_at(input.context, input.cwd, input.capture, shadow.as_path(), input.scratch)?;
115 let (globals, mut commit_args): (Vec<String>, Vec<String>) = private_invocation(input.arguments, input.pathspecs, input.mode, input.staged_all);
116 if input.quiet {
117 commit_args.push(String::from("--quiet"));
118 }
119 let request: PreparationRequest<'_> = PreparationRequest {
120 capture: input.capture,
121 shadow: shadow.as_path(),
122 commit_index: input.commit_index,
123 global_args: globals.as_slice(),
124 commit_args: commit_args.as_slice(),
125 object_directory: Some(input.capture.layout.object_directory.as_path()),
126 };
127 let status: i32 = run_native_commit(input.context, input.cwd, &request).map_err(|error| { return TransactionStop::Message(error.to_string()); })?;
128 if status != 0 {
129 return Err(TransactionStop::NativeExit(status));
130 }
131 let prepared = read_prepared_commit(input.context, shadow.as_path())?;
132 return Ok(GitBuilt { parents: parents_of(prepared.raw.as_slice()), message: message_of(prepared.raw.as_slice()), commit: prepared.oid });
133}
134
135#[cfg(test)]
137#[path = "service_native_tests.rs"]
138mod tests;