container-rs 0.1.3

simple container cli and lib!
Documentation
use clap::{App, Arg, SubCommand};
use log::{debug, error};
use std::path;
use std::process;
use container;

fn main() {
    container::init_logger();
    let app = App::new("Minimal linux container tool!")
        .version("0.1.0")
        .author("sun <github.com/wszxl516>")
        .usage("")
        .subcommand(
            SubCommand::with_name("start")
                .about("start container")
                .arg(
                    Arg::with_name("name")
                        .short("n")
                        .takes_value(true)
                        .value_name("name")
                        .default_value("container")
                        .help("container host name")
                        .required(false),
                )
                .arg(
                    Arg::with_name("root")
                        .short("r")
                        .takes_value(true)
                        .value_name("root")
                        .help("container root filesystem")
                        .required(true),
                )
                .arg(
                    Arg::with_name("init")
                        .short("i")
                        .takes_value(true)
                        .value_name("init")
                        .help("init process of container")
                        .default_value("/init")
                        .required(false),
                )
                .arg(
                    Arg::with_name("args")
                        .short("a")
                        .takes_value(true)
                        .value_name("args")
                        .help("arguments for init process!")
                        .required(false),
                )
                .arg(
                    Arg::with_name("env")
                        .short("e")
                        .takes_value(true)
                        .value_name("env")
                        .help("environment variables for init process!")
                        .required(false),
                )
                .arg(
                    Arg::with_name("out-addr")
                        .short("o")
                        .takes_value(true)
                        .value_name("out")
                        .help("veth pair of outside namespace one ip address!")
                        .default_value("10.0.0.1/24")
                        .required(false)
                )
                .arg(
                    Arg::with_name("in-addr")
                        .short("s")
                        .takes_value(true)
                        .value_name("in")
                        .help("veth pair of inside namespace one ip address!")
                        .default_value("10.0.0.2/24")
                        .required(false)
                )
            ,
        )
        .subcommand(
            SubCommand::with_name("enter")
                .about("enter a container with a command!")
                .arg(
                    Arg::with_name("pid")
                        .short("p")
                        .takes_value(true)
                        .value_name("pid")
                        .help("pid of target namespace!")
                        .required(true),
                )
                .arg(
                    Arg::with_name("cmd")
                        .short("c")
                        .takes_value(true)
                        .value_name("cmd")
                        .help("command to run!")
                        .required(true),
                )
                .arg(
                    Arg::with_name("bg")
                        .short("b")
                        .help("run in back ground")
                        .default_value("false")
                        .required(false),
                ),
        )
        .setting(clap::AppSettings::ArgRequiredElseHelp);
    let matches = app.get_matches();
    match matches.subcommand_matches("enter") {
        None => {}
        Some(arg_matches) => {
            let pid = arg_matches.value_of("pid").unwrap().parse::<i32>().unwrap();
            let cmd = arg_matches
                .value_of("cmd")
                .unwrap()
                .split(" ")
                .map(|x| x.to_string())
                .collect::<Vec<String>>();
            let bg = arg_matches.is_present("bg");
            container::Enter::new(pid, container::Args { record: cmd }, container::Env::default(), bg)
                .start(||{})
                .unwrap_or_else(|e| error!("{}", e.to_string()));
        }
    }
    match matches.subcommand_matches("start") {
        None => {}
        Some(arg_matches) => {
            let init = arg_matches.value_of("init").unwrap_or("/init");
            let env_list = arg_matches
                .value_of("env")
                .unwrap_or("")
                .split(" ")
                .map(|x| x.to_string())
                .collect::<Vec<String>>();
            let mut env = container::Env::default();
            for e in env_list {
                let (key, value) = e.split_once("=").unwrap_or(("", ""));
                if key.is_empty() || value.is_empty() {
                    continue;
                }
                env.insert(key.to_string(), value.to_string());
            }
            let args_list = arg_matches
                .value_of("args")
                .unwrap_or("")
                .split(" ")
                .map(|x| x.to_string())
                .collect::<Vec<String>>();
            let mut args = container::Args::new();
            args.insert(init.to_string());
            for arg in args_list {
                if !arg.is_empty() {
                    args.insert(arg)
                }
            }
            let name = arg_matches.value_of("name").unwrap_or("container");
            let root = arg_matches.value_of("root").unwrap();
            debug!("{} {} {} {} {}", name, root, init, args, env);
            let p =  path::Path::new(root).join(path::Path::new(init)
                .components()
                .filter(|x|x != &path::Component::RootDir)
                .map(|x|x.as_os_str().to_str().unwrap())
                .collect::<Vec<&str>>().join("/"));
            match p.is_symlink() {
                true => {}
                false => {
                    p.exists().eq(&false).then(||{
                        error!("init [{}] not exists!",  p.display());
                        process::exit(1)
                    }
                    );
                }
            }
            container::Container::new(name,
                                      root,
                                      init,
                                      args,
                                      env,
                                      arg_matches.value_of("out-addr").unwrap().to_string(),
                                      arg_matches.value_of("in-addr").unwrap().to_string())
                .start()
                .unwrap_or_else(|e| error!("{:?}", e))
        }
    }
}