1use crate::client::{Client, HglibError, Runner};
6use crate::{runcommand, MkArg};
7
8pub struct Arg<'a> {
9 pub message: &'a str,
10 pub logfile: &'a str,
11 pub addremove: bool,
12 pub closebranch: bool,
13 pub date: &'a str,
14 pub user: &'a str,
15 pub include: &'a [&'a str],
16 pub exclude: &'a [&'a str],
17 pub amend: bool,
18 pub subrepos: bool,
19 pub secret: bool,
20}
21
22impl<'a> Default for Arg<'a> {
23 fn default() -> Self {
24 Self {
25 message: "",
26 logfile: "",
27 addremove: false,
28 closebranch: false,
29 date: "",
30 user: "",
31 include: &[],
32 exclude: &[],
33 amend: false,
34 subrepos: false,
35 secret: false,
36 }
37 }
38}
39
40impl<'a> Arg<'a> {
41 fn run(&self, client: &mut Client) -> Result<(Vec<u8>, i32), HglibError> {
42 runcommand!(
43 client,
44 "commit",
45 &[""],
46 "--debug",
47 true,
48 "-m",
49 self.message,
50 "-A",
51 self.addremove,
52 "--close-branch",
53 self.closebranch,
54 "-d",
55 self.date,
56 "-u",
57 self.user,
58 "-l",
59 self.logfile,
60 "-I",
61 self.include,
62 "-X",
63 self.exclude,
64 "--amend",
65 self.amend,
66 "-S",
67 self.subrepos,
68 "--secret",
69 self.secret
70 )
71 }
72}
73
74#[derive(Debug)]
75pub struct Commit {
76 pub rev: u64,
77 pub node: String,
78}
79
80impl Client {
81 pub fn commit(&mut self, x: Arg) -> Result<Commit, HglibError> {
82 let mut x = x;
83 let message = if x.amend && x.message.is_empty() && x.logfile.is_empty() {
84 runcommand!(
85 self,
86 "log",
87 &[""],
88 "-r",
89 ".",
90 "-l",
91 1 as u32,
92 "--template",
93 "{desc}"
94 )?
95 .0
96 } else {
97 vec![0; 0]
98 };
99 if !message.is_empty() {
100 x.message = std::str::from_utf8(&message)?;
101 }
102
103 if x.message.is_empty() && x.logfile.is_empty() && !x.amend {
104 return Err(HglibError::from(
105 "Must provide at least a message or a logfile",
106 ));
107 } else if !x.message.is_empty() && !x.logfile.is_empty() {
108 return Err(HglibError::from(
109 "Cannot specify both a message and a logfile",
110 ));
111 }
112
113 let (data, _) = x.run(self)?;
114 let committed_changeset = b"committed changeset ";
115 for line in data.split(|x| *x == b'\n') {
116 if line.starts_with(committed_changeset) {
117 let rev_node = unsafe { line.get_unchecked(committed_changeset.len()..) };
118 let iter = &mut rev_node.iter();
119 let rev = iter
120 .take_while(|x| **x != b':')
121 .fold(0, |r, x| r * 10 + u64::from(*x - b'0'));
122 let node = iter.as_slice();
123 let node = String::from_utf8(node.to_vec())?;
124 return Ok(Commit { rev, node });
125 }
126 }
127 let s = std::str::from_utf8(&data).unwrap();
128 Err(HglibError::from(format!(
129 "Revision and node not found in hg output: {}",
130 s
131 )))
132 }
133}