hglib/commands/
commit.rs

1// This Source Code Form is subject to the terms of the Mozilla Public
2// License, v. 2.0. If a copy of the MPL was not distributed with this file,
3// You can obtain one at http://mozilla.org/MPL/2.0/.
4
5use 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}