1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
// @Author: Lashermes Ronan <ronan>
// @Date:   03-07-2017
// @Email:  ronan.lashermes@inria.fr
// @Last modified by:   ronan
// @Last modified time: 03-07-2017
// @License: MIT

//create parser with nom
// named!(get_arg, delimited!(tag!(" \""), is_not!("\""), char!('"')));
named!(get_arg, delimited!(tag!("\""), take_until!("\""), tag!("\"")));
named!(space_n_args, do_parse!(//combine spaces consumption and 1 arg extraction
    multispace >>
    arg: get_arg >>
    (arg)
));
named!(get_args< Vec<&str> >, many0!( map_res!(space_n_args, str::from_utf8) ) );

use nom::IResult::Done;
use nom::{alphanumeric, multispace};

use std::str;

///A PackAction is an action described in a pack_data_file. E.g. it can be 'copy "from" "to"', or 'encrypt "file" "key"', etc.
#[derive(Debug, Clone,Serialize,Deserialize)]
pub struct PackAction {
    action: String,
    args: Vec<String>
}

impl PackAction {
    pub fn new(action: String) -> PackAction {
        PackAction { action, args: Vec::new() }
    }

    pub fn add_arg(&mut self, new_arg: String) {
        self.args.push(new_arg);
    }

    pub fn parse(from: &str) -> Result<PackAction, String> {
        let (action, rest) = match alphanumeric(from.as_bytes()) {
            Done(other, matched) => (matched, other),
            _ => {return Err(format!("Failed to find action in {}", from)); },
        };

        let action_str = str::from_utf8(action).map_err(|e|e.to_string())?;
        let args_str: Vec<String> = match get_args(rest) {
            Done(_, matched) => {
                matched.iter().map(|s|s.to_string()).collect()
            },
            _ => {return Err(format!("Failed to find args in {}", from)); },
        };

        Ok(PackAction { action: action_str.to_string(), args: args_str })
    }

    pub fn get_action(&self) -> &str {
        &self.action
    }

    pub fn get_args(&self) -> &Vec<String> {
        &self.args
    }
}


#[test]
fn test_parse() {
    let must_succeed = vec!["copy \"arg1\\spaced name\" \"$APP_DIR\\arg2\"", "apply", "modify \"arg1\"", "multiple  \"arg1\"     \"arg2\" \"arg3\" \"arg4\""];

    for to_parse in must_succeed {
        assert!(PackAction::parse(to_parse).is_ok());
        // println!("{:?}", pa);
    }
}