hglib/commands/
manifest.rs1use crate::client::{Client, HglibError, Runner};
6use crate::{runcommand, MkArg};
7
8pub struct Arg<'a> {
9 pub rev: &'a str,
10 pub all: bool,
11}
12
13impl<'a> Default for Arg<'a> {
14 fn default() -> Self {
15 Self {
16 rev: "",
17 all: false,
18 }
19 }
20}
21
22impl<'a> Arg<'a> {
23 fn run(&self, client: &mut Client) -> Result<(Vec<u8>, i32), HglibError> {
24 runcommand!(
25 client,
26 "manifest",
27 &[""],
28 "-r",
29 self.rev,
30 "--all",
31 self.all,
32 "--debug",
33 true
34 )
35 }
36}
37
38#[derive(Debug, PartialEq)]
39pub struct File {
40 pub node: String,
41 pub perm: String,
42 pub symlink: bool,
43 pub executable: bool,
44 pub filename: String,
45}
46
47#[derive(Debug, PartialEq)]
48pub enum Manifest {
49 All(Vec<String>),
50 Info(Vec<File>),
51}
52
53impl Client {
54 pub fn manifest(&mut self, x: Arg) -> Result<Manifest, HglibError> {
55 let (data, _) = x.run(self)?;
56 if x.all {
57 Ok(Manifest::All(
58 data.split(|c| *c == b'\n')
59 .filter(|l| !l.is_empty())
60 .map(|s| String::from_utf8(s.to_vec()).unwrap())
61 .collect(),
62 ))
63 } else {
64 let mut res = Vec::new();
65 for line in data.split(|c| *c == b'\n').filter(|l| !l.is_empty()) {
66 if line.len() >= 48 {
67 res.push(File {
68 node: String::from_utf8(unsafe { line.get_unchecked(..40).to_vec() })?,
69 perm: String::from_utf8(unsafe { line.get_unchecked(41..44).to_vec() })?,
70 symlink: unsafe { *line.get_unchecked(45) == b'@' },
71 executable: unsafe { *line.get_unchecked(45) == b'*' },
72 filename: String::from_utf8(unsafe { line.get_unchecked(47..).to_vec() })?,
73 });
74 } else {
75 return Err(HglibError::from(format!(
76 "Hglib error: invalid length for line: {} <= 48",
77 line.len()
78 )));
79 }
80 }
81 Ok(Manifest::Info(res))
82 }
83 }
84}