<commit_before>extern crate serde_json;
extern crate silkthread_base;
extern crate silkthread_toolkit;
extern crate silkthread_lang;

use serde_json::*;

use silkthread_base::basic::*;
use silkthread_toolkit::io::*;
use silkthread_toolkit::io::tool::*;
use silkthread_lang::script::*;
use silkthread_lang::script::tool::*;

fn main() {
    // Start up
    let main_env = DynamicEnvironment::new();
    main_env.import(IoTools::new_stdio());
    main_env.import(ScriptTools::new());

    // Display a header
    let print_string = main_env.get_typed_tool::<String, ()>("print").unwrap();
    print_string.invoke(format!("{} {} by {}\n", env!("CARGO_PKG_NAME"),  env!("CARGO_PKG_VERSION"), env!("CARGO_PKG_AUTHORS")), &main_env).unwrap();

    // Start a REPL
    loop {
        let print_string    = main_env.get_typed_tool::<String, ()>(PRINT).unwrap();
        let print_value     = main_env.get_typed_tool::<Value, ()>(PRINT).unwrap();
        let read_line       = main_env.get_typed_tool::<(), ReadLineResult>(READ_LINE).unwrap();
        let lex_line        = main_env.get_typed_tool::<String, Value>(LEX_SCRIPT).unwrap();
        let display_prompt  = main_env.get_typed_tool::<(), ()>("display-prompt");

        // Display a prompt
        display_prompt
            .map(|tool| tool.invoke((), &main_env).unwrap())
            .map_err(|_| print_string.invoke(String::from("\n=» "), &main_env).unwrap())
            .unwrap_or(());

        // Read the next line
        let next_line = read_line.invoke((), &main_env);

        match next_line {
            Ok(result) => {
                // Process the line
                // TODO!
                let lexed = lex_line.invoke(result.line, &main_env).unwrap();
                print_value.invoke(lexed, &main_env).unwrap();
                print_string.invoke(String::from("\n"), &main_env).unwrap();

                // Stop on EOF
                if result.eof {
                    break;
                }
            },

            Err(erm) => {
                // Stop if we hit an error
                print_string.invoke(String::from("Error while reading from prompt: "), &main_env).unwrap();
                print_value.invoke(erm, &main_env).unwrap();
                break;
            },
        }
    }
}
<commit_msg>Pass the lexed result into the parser<commit_after>extern crate serde_json;
extern crate silkthread_base;
extern crate silkthread_toolkit;
extern crate silkthread_lang;

use serde_json::*;

use silkthread_base::*;
use silkthread_base::basic::*;
use silkthread_toolkit::io::*;
use silkthread_toolkit::io::tool::*;
use silkthread_lang::script::*;
use silkthread_lang::script::tool::*;

fn main() {
    // Start up
    let main_env = DynamicEnvironment::new();
    main_env.import(IoTools::new_stdio());
    main_env.import(ScriptTools::new());

    // Display a header
    let print_string = main_env.get_typed_tool::<String, ()>("print").unwrap();
    print_string.invoke(format!("{} {} by {}\n", env!("CARGO_PKG_NAME"),  env!("CARGO_PKG_VERSION"), env!("CARGO_PKG_AUTHORS")), &main_env).unwrap();

    // Start a REPL
    loop {
        let print_string    = main_env.get_typed_tool::<String, ()>(PRINT).unwrap();
        let print_value     = main_env.get_typed_tool::<Value, ()>(PRINT).unwrap();
        let read_line       = main_env.get_typed_tool::<(), ReadLineResult>(READ_LINE).unwrap();
        let lex_line        = main_env.get_typed_tool::<String, Value>(LEX_SCRIPT).unwrap();
        let parse_script    = main_env.get_json_tool(PARSE_SCRIPT).unwrap();
        let display_prompt  = main_env.get_typed_tool::<(), ()>("display-prompt");

        // Display a prompt
        display_prompt
            .map(|tool| tool.invoke((), &main_env).unwrap())
            .map_err(|_| print_string.invoke(String::from("\n=» "), &main_env).unwrap())
            .unwrap_or(());

        // Read the next line
        let next_line = read_line.invoke((), &main_env);

        match next_line {
            Ok(result) => {
                // Process the line
                // TODO!
                let lexed = lex_line.invoke(result.line, &main_env).unwrap();
                let parsed = parse_script.invoke_json(lexed, &main_env).unwrap();
                print_value.invoke(parsed, &main_env).unwrap();
                print_string.invoke(String::from("\n"), &main_env).unwrap();

                // Stop on EOF
                if result.eof {
                    break;
                }
            },

            Err(erm) => {
                // Stop if we hit an error
                print_string.invoke(String::from("Error while reading from prompt: "), &main_env).unwrap();
                print_value.invoke(erm, &main_env).unwrap();
                break;
            },
        }
    }
}
<|endoftext|>


<commit_before>extern crate glob;
extern crate http;
extern crate hyper;
extern crate hyper_tls;
#[macro_use]
extern crate lazy_static;
extern crate libc;
extern crate log;
#[macro_use]
extern crate serde;
extern crate serde_json;
extern crate structopt;
extern crate syslog;
extern crate toml;

mod error;
mod ghclient;
mod statics;
mod structs;

use log::{debug};
use statics::CONF_PATH;
use structopt::StructOpt;

#[derive(Debug, StructOpt)]
#[structopt(rename_all = "kebab-case")]
enum Command {
    /// Gets user public key
    Key {
        #[structopt(parse(from_str))]
        user: String,
    },
    /// Executes pam check
    Pam,
    /// Check configuration
    Check {
        #[structopt(parse(from_os_str))]
        confpath: std::path::PathBuf,
    },
    /// Cleans caches up
    #[structopt(alias = "cleanup")]
    CleanUp,
    /// Get rate limit for github api
    #[structopt(alias = "ratelimit")]
    RateLimit,
    /// Displays version details
    Version,
    /// Displays completion
    Completion {
        #[structopt(subcommand)]
        shell: Shell,
    },
}

#[allow(clippy::enum_variant_names)]
#[derive(Debug, StructOpt)]
#[structopt(rename_all = "kebab-case")]
enum Shell {
    Bash,
    Fish,
    Zsh,
    PowerShell,
    Elvish,
}

fn main() {
    let command = Command::from_args();

    use ghclient::GithubClient;
    use std::env;
    use std::process;
    use std::str::FromStr;
    use structs::Config;

    let log_level_env = env::var("LOG_LEVEL").unwrap_or(String::from("OFF"));
    let log_level = log::LevelFilter::from_str(&log_level_env).unwrap_or(log::LevelFilter::Off);
    syslog::init(syslog::Facility::LOG_AUTH, log_level, Some("sectora")).expect("init log");

    debug!("{:?}", command);
    match command {
        Command::Check { confpath } => match Config::from_path(&confpath) {
            Ok(_) => process::exit(0),
            Err(_) => process::exit(11),
        },
        Command::Key { user } => {
            match Config::from_path(&CONF_PATH).and_then(|conf| Ok(GithubClient::new(&conf)))
                                               .and_then(|client| client.print_user_public_key(&user))
            {
                Ok(_) => process::exit(0),
                Err(_) => process::exit(21),
            }
        }
        Command::Pam => match env::var("PAM_USER") {
            Ok(user) => match Config::from_path(&CONF_PATH).and_then(|conf| Ok(GithubClient::new(&conf)))
                                                           .and_then(|client| client.check_pam(&user))
            {
                Ok(true) => process::exit(0),
                Ok(false) => process::exit(1),
                Err(_) => process::exit(31),
            },
            Err(_) => process::exit(41),
        },
        Command::CleanUp => match Config::from_path(&CONF_PATH).and_then(|conf| Ok(GithubClient::new(&conf)))
                                                               .and_then(|client| client.clear_all_caches())
        {
            Ok(_) => process::exit(0),
            Err(_) => process::exit(51),
        },
        Command::RateLimit => match Config::from_path(&CONF_PATH).and_then(|conf| Ok(GithubClient::new(&conf)))
                                                                 .and_then(|client| client.print_rate_limit())
        {
            Ok(_) => process::exit(0),
            Err(_) => process::exit(61),
        },
        Command::Version => {
            println!("{}",
                     concat!(env!("CARGO_PKG_VERSION"),
                             include_str!(concat!(env!("OUT_DIR"), "/commit-info.txt"))));
        }
        Command::Completion { shell } => {
            let shell = match shell {
                Shell::Bash => structopt::clap::Shell::Bash,
                Shell::Fish => structopt::clap::Shell::Fish,
                Shell::Zsh => structopt::clap::Shell::Zsh,
                Shell::PowerShell => structopt::clap::Shell::PowerShell,
                Shell::Elvish => structopt::clap::Shell::Elvish,
            };
            Command::clap().gen_completions_to("sectora", shell, &mut std::io::stdout());
        }
    };
}
<commit_msg>Format<commit_after>extern crate glob;
extern crate http;
extern crate hyper;
extern crate hyper_tls;
#[macro_use]
extern crate lazy_static;
extern crate libc;
extern crate log;
#[macro_use]
extern crate serde;
extern crate serde_json;
extern crate structopt;
extern crate syslog;
extern crate toml;

mod error;
mod ghclient;
mod statics;
mod structs;

use log::debug;
use statics::CONF_PATH;
use structopt::StructOpt;

#[derive(Debug, StructOpt)]
#[structopt(rename_all = "kebab-case")]
enum Command {
    /// Gets user public key
    Key {
        #[structopt(parse(from_str))]
        user: String,
    },
    /// Executes pam check
    Pam,
    /// Check configuration
    Check {
        #[structopt(parse(from_os_str))]
        confpath: std::path::PathBuf,
    },
    /// Cleans caches up
    #[structopt(alias = "cleanup")]
    CleanUp,
    /// Get rate limit for github api
    #[structopt(alias = "ratelimit")]
    RateLimit,
    /// Displays version details
    Version,
    /// Displays completion
    Completion {
        #[structopt(subcommand)]
        shell: Shell,
    },
}

#[allow(clippy::enum_variant_names)]
#[derive(Debug, StructOpt)]
#[structopt(rename_all = "kebab-case")]
enum Shell {
    Bash,
    Fish,
    Zsh,
    PowerShell,
    Elvish,
}

fn main() {
    let command = Command::from_args();

    use ghclient::GithubClient;
    use std::env;
    use std::process;
    use std::str::FromStr;
    use structs::Config;

    let log_level_env = env::var("LOG_LEVEL").unwrap_or(String::from("OFF"));
    let log_level = log::LevelFilter::from_str(&log_level_env).unwrap_or(log::LevelFilter::Off);
    syslog::init(syslog::Facility::LOG_AUTH, log_level, Some("sectora")).expect("init log");

    debug!("{:?}", command);
    match command {
        Command::Check { confpath } => match Config::from_path(&confpath) {
            Ok(_) => process::exit(0),
            Err(_) => process::exit(11),
        },
        Command::Key { user } => {
            match Config::from_path(&CONF_PATH).and_then(|conf| Ok(GithubClient::new(&conf)))
                                               .and_then(|client| client.print_user_public_key(&user))
            {
                Ok(_) => process::exit(0),
                Err(_) => process::exit(21),
            }
        }
        Command::Pam => match env::var("PAM_USER") {
            Ok(user) => match Config::from_path(&CONF_PATH).and_then(|conf| Ok(GithubClient::new(&conf)))
                                                           .and_then(|client| client.check_pam(&user))
            {
                Ok(true) => process::exit(0),
                Ok(false) => process::exit(1),
                Err(_) => process::exit(31),
            },
            Err(_) => process::exit(41),
        },
        Command::CleanUp => match Config::from_path(&CONF_PATH).and_then(|conf| Ok(GithubClient::new(&conf)))
                                                               .and_then(|client| client.clear_all_caches())
        {
            Ok(_) => process::exit(0),
            Err(_) => process::exit(51),
        },
        Command::RateLimit => match Config::from_path(&CONF_PATH).and_then(|conf| Ok(GithubClient::new(&conf)))
                                                                 .and_then(|client| client.print_rate_limit())
        {
            Ok(_) => process::exit(0),
            Err(_) => process::exit(61),
        },
        Command::Version => {
            println!("{}",
                     concat!(env!("CARGO_PKG_VERSION"),
                             include_str!(concat!(env!("OUT_DIR"), "/commit-info.txt"))));
        }
        Command::Completion { shell } => {
            let shell = match shell {
                Shell::Bash => structopt::clap::Shell::Bash,
                Shell::Fish => structopt::clap::Shell::Fish,
                Shell::Zsh => structopt::clap::Shell::Zsh,
                Shell::PowerShell => structopt::clap::Shell::PowerShell,
                Shell::Elvish => structopt::clap::Shell::Elvish,
            };
            Command::clap().gen_completions_to("sectora", shell, &mut std::io::stdout());
        }
    };
}
<|endoftext|>


<commit_before>use std::collections::HashMap;
use std::rc::Rc;
use std::str::SplitWhitespace;
use std::slice::Iter;
use std::cell::RefCell;

pub struct Command<'a> {
    command: Vec<&'a str>,
    exec: Box<RefCell<FnMut(Vec<&str>) + 'a>>,
    complete: Option<Box<FnMut(Vec<&str>) + 'a>>
}

impl<'a> Command<'a> {
    fn new<T: FnMut(Vec<&str>) + 'a, U: FnMut(Vec<&str>) + 'a>(cmd: Vec<&'a str>, exec_handler: T, complete_handler: Option<U>) -> Command<'a> {
        let mut obj = Command {
            command: cmd,
            exec: Box::new(RefCell::new(exec_handler)),
            complete: None
        };

        if let Some(cb) = complete_handler {
            obj.complete = Some(Box::new(cb));
        }

        obj
    }
}

pub struct Cli<'a> {
    commands: HashMap<&'a str, Cli<'a>>,
    handler: Option<Rc<Command<'a>>>
}

impl<'a> Cli<'a>{

    fn new() -> Cli<'a> {
        Cli {
            commands: HashMap::new(),
            handler: None
        }
    }

    fn register<T: FnMut(Vec<&str>) + 'a>(&mut self, cmd: Vec<&'a str>, exec: T) -> Result<(), ()> {
        let tmp = Rc::new(Command::new(cmd.clone(), exec, None::<T>));

        match self._register(cmd.iter(), tmp.clone()) {
            Ok(_) => Ok(()),
            Err(_) => {
                //TODO: this can only happen if we register "Vec::new()" ... probably disallow that at all
                self.handler = Some(tmp.clone());
                Err(())
            }
        }
    }

    fn _register(&mut self, mut it: Iter<&'a str>, command: Rc<Command<'a>>) -> Result<(), ()> {
        if let Some(portion) = it.next() {
            if !self.commands.contains_key(portion) {
                let mut cli = Cli::new();
                if let Err(_) = cli._register(it, command.clone()) {
                    cli.handler = Some(command.clone())
                }
                self.commands.insert(portion, cli);
            } else {
                if let Some(cmd) = self.commands.get_mut(portion) {
                    if let Err(_) = cmd._register(it, command.clone()) {
                        cmd.handler = Some(command.clone())
                    }
                }
            };
            Ok(())
        } else {
            Err(())
        }
    }

    fn complete(&self, argv: &str) -> Vec<&str> {
        println!("complete for '{}'", argv.trim());
        let portions = argv.trim().split_whitespace();

        match self._complete(portions) {
            Ok(ret) => ret,
            Err(_) => Vec::new()
        }
    }

    fn _complete(&self, mut portions: SplitWhitespace) -> Result<Vec<&str>, ()> {
        if let Some(ref portion) = portions.next() {
            if let Some(ref cmd) = self.commands.get(portion) {
                cmd._complete(portions)
            } else {
                Ok(self.commands.keys()
                    .filter(|cmd| cmd.starts_with(portion))
                    .cloned()
                    .collect())
            }
        } else {
            Ok(self.commands.keys()
                .cloned()
                .collect())
        }
    }

    fn exec(&mut self, cmd: &str) {
        let argv:Vec<&str> = cmd.clone().split_whitespace().collect();
        let portions = cmd.trim().split_whitespace();
        self._exec(portions, argv);
    }

    fn _exec(&mut self, mut portions: SplitWhitespace, argv: Vec<&str>) {
        if let Some(portion) = portions.next() {
            if let Some(cmd) = self.commands.get_mut(portion) {
                cmd._exec(portions, argv);
            } else {
                if let Some(ref mut cb) = self.handler {
                    println!("handler for {:?}", cb.command);
                    (&mut *cb.exec.borrow_mut())(argv);
                }
            }
        } else {
            if let Some(ref mut cb) = self.handler {
                println!("handler for {:?}", cb.command);
                (&mut *cb.exec.borrow_mut())(argv);
            }
        }
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_register_and_execute() {
        let mut called = false;
        {
            let mut cli = Cli::new();
            cli.register(vec!["foo", "bar"], | _ | { called=true } ).ok();
            cli.exec("foo bar");
        }
        assert!(called == true)
    }

    #[test]
    fn test_complete_empty_single_cmd() {
        let mut cli = Cli::new();
        cli.register(vec!["foo"], | _ | { } ).ok();
        assert!(vec!["foo"] == cli.complete(""));
        assert!(vec!["foo"] == cli.complete("f"));
        assert!(vec!["foo"] == cli.complete("  f"));
        assert!(vec!["foo"] == cli.complete("f   "));  //TODO: this is a bit weird - probably shouldn't happen
        assert!(cli.complete("foo").is_empty());
    }

    #[test]
    fn test_complete_multi_cmd() {
        let mut cli = Cli::new();
        cli.register(vec!["foo", "bar"], | _| { } ).ok();
        assert!(vec!["foo"] == cli.complete("f"));
        assert!(vec!["bar"] == cli.complete("foo"));
        assert!(vec!["bar"] == cli.complete("foo b"));
    }

    #[test]
    fn test_register_and_execute_with_arguments() {
        let mut called = false;
        {
            let mut cli = Cli::new();
            cli.register(vec!["foo"], | args | {
                called=true;
                assert!(vec!["foo", "bar", "baz"] == args);
            } ).ok();
            cli.exec("foo bar baz");
        }
        assert!(called == true);
    }
}

fn foo(argv: Vec<&str>) {
    println!("--> {:?}", argv);
}

fn main() {
    let mut cli = Cli::new();

    cli.register(vec!["show", "stuff"], foo).ok();
    //cli.register(vec!["show", "other"], foo).ok();
    //cli.register(vec!["some", "other"], foo).ok();
    //cli.register(vec!["list", "other", "cool"], foo).ok();
    //cli.register(vec!["list", "other", "uncool"], foo).ok();

    loop {
        let mut line = String::new();
        std::io::stdin().read_line(&mut line).unwrap();

        //println!("got: {:?}", cli.complete(&line));
        cli.exec(&line);
    }
}
<commit_msg>add more tests<commit_after>use std::collections::HashMap;
use std::rc::Rc;
use std::str::SplitWhitespace;
use std::slice::Iter;
use std::cell::RefCell;

pub struct Command<'a> {
    command: Vec<&'a str>,
    exec: Box<RefCell<FnMut(Vec<&str>) + 'a>>,
    complete: Option<Box<FnMut(Vec<&str>) + 'a>>
}

impl<'a> Command<'a> {
    fn new<T: FnMut(Vec<&str>) + 'a, U: FnMut(Vec<&str>) + 'a>(cmd: Vec<&'a str>, exec_handler: T, complete_handler: Option<U>) -> Command<'a> {
        let mut obj = Command {
            command: cmd,
            exec: Box::new(RefCell::new(exec_handler)),
            complete: None
        };

        if let Some(cb) = complete_handler {
            obj.complete = Some(Box::new(cb));
        }

        obj
    }
}

pub struct Cli<'a> {
    commands: HashMap<&'a str, Cli<'a>>,
    handler: Option<Rc<Command<'a>>>
}

impl<'a> Cli<'a>{

    fn new() -> Cli<'a> {
        Cli {
            commands: HashMap::new(),
            handler: None
        }
    }

    fn register<T: FnMut(Vec<&str>) + 'a>(&mut self, cmd: Vec<&'a str>, exec: T) -> Result<(), ()> {
        let tmp = Rc::new(Command::new(cmd.clone(), exec, None::<T>));

        match self._register(cmd.iter(), tmp.clone()) {
            Ok(_) => Ok(()),
            Err(_) => {
                //TODO: this can only happen if we register "Vec::new()" ... probably disallow that at all
                self.handler = Some(tmp.clone());
                Err(())
            }
        }
    }

    fn _register(&mut self, mut it: Iter<&'a str>, command: Rc<Command<'a>>) -> Result<(), ()> {
        if let Some(portion) = it.next() {
            if !self.commands.contains_key(portion) {
                let mut cli = Cli::new();
                if let Err(_) = cli._register(it, command.clone()) {
                    cli.handler = Some(command.clone())
                }
                self.commands.insert(portion, cli);
            } else {
                if let Some(cmd) = self.commands.get_mut(portion) {
                    if let Err(_) = cmd._register(it, command.clone()) {
                        cmd.handler = Some(command.clone())
                    }
                }
            };
            Ok(())
        } else {
            Err(())
        }
    }

    fn complete(&self, argv: &str) -> Vec<&str> {
        println!("complete for '{}'", argv.trim());
        let portions = argv.trim().split_whitespace();

        match self._complete(portions) {
            Ok(ret) => ret,
            Err(_) => Vec::new()
        }
    }

    fn _complete(&self, mut portions: SplitWhitespace) -> Result<Vec<&str>, ()> {
        if let Some(ref portion) = portions.next() {
            if let Some(ref cmd) = self.commands.get(portion) {
                cmd._complete(portions)
            } else {
                Ok(self.commands.keys()
                    .filter(|cmd| cmd.starts_with(portion))
                    .cloned()
                    .collect())
            }
        } else {
            Ok(self.commands.keys()
                .cloned()
                .collect())
        }
    }

    fn exec(&mut self, cmd: &str) {
        let argv:Vec<&str> = cmd.clone().split_whitespace().collect();
        let portions = cmd.trim().split_whitespace();
        self._exec(portions, argv);
    }

    fn _exec(&mut self, mut portions: SplitWhitespace, argv: Vec<&str>) {
        if let Some(portion) = portions.next() {
            if let Some(cmd) = self.commands.get_mut(portion) {
                cmd._exec(portions, argv);
            } else {
                if let Some(ref mut cb) = self.handler {
                    println!("handler for {:?}", cb.command);
                    (&mut *cb.exec.borrow_mut())(argv);
                }
            }
        } else {
            if let Some(ref mut cb) = self.handler {
                println!("handler for {:?}", cb.command);
                (&mut *cb.exec.borrow_mut())(argv);
            }
        }
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_register_and_execute() {
        let mut called = false;
        {
            let mut cli = Cli::new();
            cli.register(vec!["foo", "bar"], | _ | { called=true } ).ok();
            cli.exec("foo bar");
        }
        assert!(called == true)
    }

    #[test]
    fn test_register_and_execute_multiple_times() {
        let mut called = 0u8;
        {
            let mut cli = Cli::new();
            cli.register(vec!["foo", "bar"], | _ | { called = called + 1} ).ok();
            cli.exec("foo bar");
            cli.exec("foo bar");
        }
        assert!(called == 2)
    }

    #[test]
    fn test_complete_empty_single_cmd() {
        let mut cli = Cli::new();
        cli.register(vec!["foo"], | _ | { } ).ok();
        assert!(vec!["foo"] == cli.complete(""));
        assert!(vec!["foo"] == cli.complete("f"));
        assert!(vec!["foo"] == cli.complete("  f"));
        //assert!(vec![""] == cli.complete("f   "));  //FIXME: this test should pass
        assert!(cli.complete("foo").is_empty());
    }

    #[test]
    fn test_complete_multi_cmd() {
        let mut cli = Cli::new();
        cli.register(vec!["foo", "bar"], | _| { } ).ok();
        assert!(vec!["foo"] == cli.complete("f"));
        assert!(vec!["bar"] == cli.complete("foo"));
        assert!(vec!["bar"] == cli.complete("foo b"));
    }

    #[test]
    fn test_register_and_execute_with_arguments() {
        let mut called = false;
        {
            let mut cli = Cli::new();
            cli.register(vec!["foo"], | args | {
                called=true;
                assert!(vec!["foo", "bar", "baz"] == args);
            } ).ok();
            cli.exec("foo bar baz");
        }
        assert!(called == true);
    }
}

fn foo(argv: Vec<&str>) {
    println!("--> {:?}", argv);
}

fn main() {
    let mut cli = Cli::new();

    cli.register(vec!["show", "stuff"], foo).ok();
    //cli.register(vec!["show", "other"], foo).ok();
    //cli.register(vec!["some", "other"], foo).ok();
    //cli.register(vec!["list", "other", "cool"], foo).ok();
    //cli.register(vec!["list", "other", "uncool"], foo).ok();

    loop {
        let mut line = String::new();
        std::io::stdin().read_line(&mut line).unwrap();

        //println!("got: {:?}", cli.complete(&line));
        cli.exec(&line);
    }
}
<|endoftext|>


<commit_before>extern crate chrono;

use std::io::{BufRead, BufReader, stderr, Write};
use std::process::{Command, Stdio, exit};
use std::sync::mpsc::{channel, Sender};
use std::thread::{self, sleep};
use std::time::Duration;

mod configuration;

enum Update {
    Workspaces(String),
    Time(String),
    Title(String),
}

fn workspace_info(sender: Sender<Update>) {
    let output = Command::new("bspc").args(&["subscribe", "report"]).stdout(Stdio::piped()).spawn().expect("Failed to run bspc");

    let icons: configuration::Icons = configuration::get_icons();
    let colors: configuration::Colors = configuration::get_colors();

    let reader = BufReader::new(output.stdout.expect("Failed to read stdout of bspc"));
    for line in reader.lines() {
        let mut message: Vec<String> = Vec::new();
        message.push("%{l} ".to_owned());
        message.push("%{A4:bspc desktop -f prev:}%{A5:bspc desktop -f next:}".to_owned());

        let line = line.expect("Failed to read line from bspc");
        let line_vector = line.split(":").collect::<Vec<&str>>();

        for line in &line_vector {
            match &line[0..1] {
                // Occupied focused
                "O" => {
                    message.push(format!("%{{A:bspc desktop -f {}:}}", &line[1..]));
                    message.push(format!("%{{F{}}}{}%{{F-}}", colors.occupied_focused, icons.occupied_focused));
                    message.push("%{A} ".to_owned());
                }

                // Occupied unfocused
                "o" => {
                    message.push(format!("%{{A:bspc desktop -f {}:}}", &line[1..]));
                    message.push(format!("%{{F{}}}{}%{{F-}}", colors.occupied_unfocused, icons.occupied_unfocused));
                    message.push("%{A} ".to_owned());
                }

                // Free focused
                "F" => {
                    message.push(format!("%{{A:bspc desktop -f {}:}}", &line[1..]));
                    message.push(format!("%{{F{}}}{}%{{F-}}", colors.free_focused, icons.free_focused));
                    message.push("%{A} ".to_owned());
                }

                // Free unfocused
                "f" => {
                    message.push(format!("%{{A:bspc desktop -f {}:}}", &line[1..]));
                    message.push(format!("%{{F{}}}{}%{{F-}}", colors.free_unfocused, icons.free_unfocused));
                    message.push("%{A} ".to_owned());
                }

                // Urgent focused
                "U" => {
                    message.push(format!("%{{A:bspc desktop -f {}:}}", &line[1..]));
                    message.push(format!("%{{F{}}}{}%{{F-}}", colors.urgent_focused, icons.urgent_focused));
                    message.push("%{A} ".to_owned());
                }

                // Urgent unfocused
                "u" => {
                    message.push(format!("%{{A:bspc desktop -f {}:}}", &line[1..]));
                    message.push(format!("%{{F{}}}{}%{{F-}}", colors.urgent_unfocused, icons.urgent_unfocused));
                    message.push("%{A} ".to_owned());
                }

                _ => {}
            }
        }
        message.push("%{A}%{A}".to_owned());

        let _ = sender.send(Update::Workspaces(message.join("")));
    }
}

fn title(sender: Sender<Update>, length: &str) {
    let output = Command::new("xtitle").args(&["-s", "-i", "-t", length]).stdout(Stdio::piped()).spawn().expect("Failed to run xtitle");

    let reader = BufReader::new(output.stdout.expect("Failed to read stdout of xtitle"));
    for line in reader.lines() {
        let line = line.expect("Failed to read line from xtitle");
        let _ = sender.send(Update::Title(format!("%{{c}}{}", line)));
    }
}

fn time(sender: Sender<Update>) {
    loop {
        let time = chrono::Local::now().format("%I:%M %p");
        let _ = sender.send(Update::Time(format!("%{{r}}%{{B#FF665B5B}} {} %{{B-}}", time)));
        sleep(Duration::from_secs(1));
    }
}

fn main() {
    let lemonbar_options = configuration::get_lemonbar_options();

    let lemonbar = match Command::new("lemonbar")
        .arg("-g").arg(format!("{}x{}+{}+{}", &lemonbar_options.width,
                                              &lemonbar_options.height,
                                              &lemonbar_options.x,
                                              &lemonbar_options.y))
        .arg("-a").arg(&lemonbar_options.clickable_areas)
        .arg("-f").arg(&lemonbar_options.text_font)
        .arg("-f").arg(&lemonbar_options.icon_font)
        .arg("-B").arg(&lemonbar_options.background_color)
        .stdin(Stdio::piped())
        .spawn() {
        Ok(bar) => bar,
        Err(_) => {
            let _ = stderr().write("Failed to run lemonbar".as_bytes()).unwrap();
            exit(1);
        },
    };

    let mut lemonbar_stdin = lemonbar.stdin.unwrap();

    let (sender, receiver) = channel::<Update>();
    let (sender_clone1, sender_clone2, sender_clone3) = (sender.clone(), sender.clone(), sender.clone());

    let mut workspace_message = String::new();
    let mut title_message = String::new();
    let mut time_message = String::new();
    let mut message = String::new();

    let _ = thread::spawn(move || { workspace_info(sender_clone1); });
    let _ = thread::spawn(move || { title(sender_clone2, &lemonbar_options.title_length); });
    let _ = thread::spawn(move || { time(sender_clone3); });

    for line in receiver.iter() {
        match line {
            Update::Workspaces(info) => {
                workspace_message = info;
            }

            Update::Title(title) => {
                title_message = title;
            }

            Update::Time(time) => {
                time_message = time;
            }
        }

        if message != workspace_message.to_owned() + &title_message + &time_message {
            message = workspace_message.to_owned() + &title_message + &time_message;
            sleep(Duration::from_millis(5));
            let _ = lemonbar_stdin.write(format!("{}\n", message).as_bytes()).unwrap();
            // println!("{}", message);
        }
    }
}
<commit_msg>Very minor changes<commit_after>extern crate chrono;

use std::io::{BufRead, BufReader, stderr, Write};
use std::process::{Command, Stdio, exit};
use std::sync::mpsc::{channel, Sender};
use std::thread::{self, sleep};
use std::time::Duration;

mod configuration;

enum Update {
    Workspaces(String),
    Time(String),
    Title(String),
}

fn workspace_info(sender: Sender<Update>) {
    let output = Command::new("bspc").args(&["subscribe", "report"]).stdout(Stdio::piped()).spawn().expect("Failed to run bspc");

    let icons: configuration::Icons = configuration::get_icons();
    let colors: configuration::Colors = configuration::get_colors();

    let reader = BufReader::new(output.stdout.expect("Failed to read stdout of bspc"));
    for line in reader.lines() {
        let mut message: Vec<String> = Vec::new();
        message.push("%{l} ".to_owned());
        message.push("%{A4:bspc desktop -f prev:}%{A5:bspc desktop -f next:}".to_owned());

        let line = line.expect("Failed to read line from bspc");
        let line_vector = line.split(":").collect::<Vec<&str>>();

        for line in &line_vector {
            match &line[0..1] {
                // Occupied focused
                "O" => {
                    message.push(format!("%{{A:bspc desktop -f {}:}}", &line[1..]));
                    message.push(format!("%{{F{}}}{}%{{F-}}", colors.occupied_focused, icons.occupied_focused));
                    message.push("%{A} ".to_owned());
                }

                // Occupied unfocused
                "o" => {
                    message.push(format!("%{{A:bspc desktop -f {}:}}", &line[1..]));
                    message.push(format!("%{{F{}}}{}%{{F-}}", colors.occupied_unfocused, icons.occupied_unfocused));
                    message.push("%{A} ".to_owned());
                }

                // Free focused
                "F" => {
                    message.push(format!("%{{A:bspc desktop -f {}:}}", &line[1..]));
                    message.push(format!("%{{F{}}}{}%{{F-}}", colors.free_focused, icons.free_focused));
                    message.push("%{A} ".to_owned());
                }

                // Free unfocused
                "f" => {
                    message.push(format!("%{{A:bspc desktop -f {}:}}", &line[1..]));
                    message.push(format!("%{{F{}}}{}%{{F-}}", colors.free_unfocused, icons.free_unfocused));
                    message.push("%{A} ".to_owned());
                }

                // Urgent focused
                "U" => {
                    message.push(format!("%{{A:bspc desktop -f {}:}}", &line[1..]));
                    message.push(format!("%{{F{}}}{}%{{F-}}", colors.urgent_focused, icons.urgent_focused));
                    message.push("%{A} ".to_owned());
                }

                // Urgent unfocused
                "u" => {
                    message.push(format!("%{{A:bspc desktop -f {}:}}", &line[1..]));
                    message.push(format!("%{{F{}}}{}%{{F-}}", colors.urgent_unfocused, icons.urgent_unfocused));
                    message.push("%{A} ".to_owned());
                }

                _ => {}
            }
        }
        message.push("%{A}%{A}".to_owned());

        let _ = sender.send(Update::Workspaces(message.join("")));
    }
}

fn title(sender: Sender<Update>, length: &str) {
    let output = Command::new("xtitle").args(&["-s", "-i", "-t", length]).stdout(Stdio::piped()).spawn().expect("Failed to run xtitle");

    let reader = BufReader::new(output.stdout.expect("Failed to read stdout of xtitle"));
    for line in reader.lines() {
        let line = line.expect("Failed to read line from xtitle");
        let _ = sender.send(Update::Title(format!("%{{c}}{}", line)));
    }
}

fn time(sender: Sender<Update>) {
    loop {
        let time = chrono::Local::now().format("%-I:%M %p");
        let _ = sender.send(Update::Time(format!("%{{r}}%{{B#FF665B5B}} {} %{{B-}}", time)));
        sleep(Duration::from_secs(1));
    }
}

fn main() {
    let lemonbar_options = configuration::get_lemonbar_options();

    let lemonbar = match Command::new("lemonbar")
        .arg("-g").arg(format!("{}x{}+{}+{}", &lemonbar_options.width,
                                              &lemonbar_options.height,
                                              &lemonbar_options.x,
                                              &lemonbar_options.y))
        .arg("-a").arg(&lemonbar_options.clickable_areas)
        .arg("-f").arg(&lemonbar_options.text_font)
        .arg("-f").arg(&lemonbar_options.icon_font)
        .arg("-B").arg(&lemonbar_options.background_color)
        .stdin(Stdio::piped())
        .spawn() {
        Ok(bar) => bar,
        Err(_) => {
            let _ = stderr().write("Failed to run lemonbar".as_bytes()).unwrap();
            exit(1);
        },
    };

    let mut lemonbar_stdin = lemonbar.stdin.unwrap();

    let (sender, receiver) = channel::<Update>();
    let (sender_clone1, sender_clone2, sender_clone3) = (sender.clone(), sender.clone(), sender.clone());

    let mut workspace_message = String::new();
    let mut title_message = String::new();
    let mut time_message = String::new();
    let mut message = String::new();

    let _ = thread::spawn(move || { workspace_info(sender_clone1); });
    let _ = thread::spawn(move || { title(sender_clone2, &lemonbar_options.title_length); });
    let _ = thread::spawn(move || { time(sender_clone3); });

    for line in receiver.iter() {
        match line {
            Update::Workspaces(info) => {
                workspace_message = info;
            }

            Update::Title(title) => {
                title_message = title;
            }

            Update::Time(time) => {
                time_message = time;
            }
        }

        if message != workspace_message.to_owned() + &title_message + &time_message {
            message = workspace_message.to_owned() + &title_message + &time_message;
            sleep(Duration::from_millis(5));
            let _ = lemonbar_stdin.write(format!("{}\n", message).as_bytes()).unwrap();
        }
    }
}
<|endoftext|>


<commit_before>//
//    Copyright (C) 2015  Rory McCann
//
//    This program is free software: you can redistribute it and/or modify
//    it under the terms of the GNU Affero General Public License as published by
//    the Free Software Foundation, either version 3 of the License, or
//    (at your option) any later version.
//
//    This program is distributed in the hope that it will be useful,
//    but WITHOUT ANY WARRANTY; without even the implied warranty of
//    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
//    GNU Affero General Public License for more details.
//
//    You should have received a copy of the GNU Affero General Public License
//    along with this program.  If not, see <http://www.gnu.org/licenses/>.

extern crate num;

use std::env;
use std::fmt;
use num::integer::{div_rem, Integer};

struct Duration<T> {
    weeks: T,
    days: T,
    hours: T,
    minutes: T,
    seconds: T,
}

impl<T:Integer> Duration<T> {
    fn new() -> Duration<T> {
        Duration{ weeks: T::zero(), days: T::zero(), hours: T::zero(), minutes: T::zero(), seconds: T::zero() }
    }

    fn set_weeks<'a>(&'a mut self, weeks: T) -> &'a mut Duration<T> {
        self.weeks = weeks;
        self
    }
    fn set_days<'a>(&'a mut self, days: T) -> &'a mut Duration<T> {
        self.days = days;
        self
    }
    fn set_hours<'a>(&'a mut self, hours: T) -> &'a mut Duration<T> {
        self.hours = hours;
        self
    }
    fn set_minutes<'a>(&'a mut self, minutes: T) -> &'a mut Duration<T> {
        self.minutes = minutes;
        self
    }
    fn set_seconds<'a>(&'a mut self, seconds: T) -> &'a mut Duration<T> {
        self.seconds = seconds;
        self
    }

}

impl fmt::Display for Duration<u64> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let mut writing = false;
        if self.weeks != 0 {
            try!(write!(f, "{}wk", self.weeks));
            writing = true;
        }
        if self.days != 0 || writing {
            try!(write!(f, "{}dy", self.days));
            writing = true;
        }
        if self.hours != 0 || writing {
            try!(write!(f, "{}h", self.hours));
            writing = true;
        }
        if self.minutes != 0 || writing {
            try!(write!(f, "{}m", self.minutes));
            writing = true;
        }
        if self.seconds != 0 || writing {
            if writing {
                try!(write!(f, "{:02}s", self.seconds));
            } else {
                try!(write!(f, "{}s", self.seconds));
            }
            writing = true;
        }
        Ok(())
    }
}

fn sec2duration(seconds: u64) -> Duration<u64> {
    let (minutes, seconds) = div_rem(seconds, 60);
    let (hours, minutes) = div_rem(minutes, 60);
    let (days, hours) = div_rem(hours, 24);
    let (weeks, days) = div_rem(days, 7);

    Duration{ weeks: weeks, days: days, hours: hours, minutes: minutes, seconds: seconds }
}

fn prettytime(input: Vec<String>) -> Result<String, String> {
    if input.len() < 1 { return Err("No input".to_string()); }

    let ref args1: String = input[0];
    let seconds: u64 = try!(args1.parse().or(Err("Not an integer".to_string())));

    let duration = sec2duration(seconds);

    Ok(format!("{}", duration))
}

fn main() {
    let args: Vec<_> = env::args().skip(1).collect();
    match prettytime(args) {
        Ok(s) => { println!("{}", s); },
        Err(s) => { println!("{}", s); }
    }
}

#[test]
fn test_print_duration() {
    assert_eq!("", format!("{}", Duration::new()));
    assert_eq!("1s", format!("{}", Duration::new().set_seconds(1)));
    assert_eq!("1m00s", format!("{}", Duration::new().set_minutes(1)));
    assert_eq!("1m03s", format!("{}", Duration::new().set_minutes(1).set_seconds(3)));
    assert_eq!("1hr00m00s", format!("{}", Duration::new().set_hours(1)));
}
<commit_msg>tests<commit_after>//
//    Copyright (C) 2015  Rory McCann
//
//    This program is free software: you can redistribute it and/or modify
//    it under the terms of the GNU Affero General Public License as published by
//    the Free Software Foundation, either version 3 of the License, or
//    (at your option) any later version.
//
//    This program is distributed in the hope that it will be useful,
//    but WITHOUT ANY WARRANTY; without even the implied warranty of
//    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
//    GNU Affero General Public License for more details.
//
//    You should have received a copy of the GNU Affero General Public License
//    along with this program.  If not, see <http://www.gnu.org/licenses/>.

extern crate num;

use std::env;
use std::fmt;
use num::integer::{div_rem, Integer};

struct Duration<T> {
    weeks: T,
    days: T,
    hours: T,
    minutes: T,
    seconds: T,
}

impl<T:Integer> Duration<T> {
    fn new() -> Duration<T> {
        Duration{ weeks: T::zero(), days: T::zero(), hours: T::zero(), minutes: T::zero(), seconds: T::zero() }
    }

    fn set_weeks<'a>(&'a mut self, weeks: T) -> &'a mut Duration<T> {
        self.weeks = weeks;
        self
    }
    fn set_days<'a>(&'a mut self, days: T) -> &'a mut Duration<T> {
        self.days = days;
        self
    }
    fn set_hours<'a>(&'a mut self, hours: T) -> &'a mut Duration<T> {
        self.hours = hours;
        self
    }
    fn set_minutes<'a>(&'a mut self, minutes: T) -> &'a mut Duration<T> {
        self.minutes = minutes;
        self
    }
    fn set_seconds<'a>(&'a mut self, seconds: T) -> &'a mut Duration<T> {
        self.seconds = seconds;
        self
    }

}

impl fmt::Display for Duration<u64> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let mut writing = false;
        if self.weeks != 0 {
            try!(write!(f, "{}wk", self.weeks));
            writing = true;
        }
        if self.days != 0 || writing {
            try!(write!(f, "{}dy", self.days));
            writing = true;
        }
        if self.hours != 0 || writing {
            try!(write!(f, "{}hr", self.hours));
            writing = true;
        }
        if self.minutes != 0 || writing {
            if writing {
                try!(write!(f, "{:02}m", self.minutes));
            } else {
                try!(write!(f, "{}m", self.minutes));
            }
            writing = true;
        }
        if self.seconds != 0 || writing {
            if writing {
                try!(write!(f, "{:02}s", self.seconds));
            } else {
                try!(write!(f, "{}s", self.seconds));
            }
            //writing = true;
        }
        Ok(())
    }
}

fn sec2duration(seconds: u64) -> Duration<u64> {
    let (minutes, seconds) = div_rem(seconds, 60);
    let (hours, minutes) = div_rem(minutes, 60);
    let (days, hours) = div_rem(hours, 24);
    let (weeks, days) = div_rem(days, 7);

    Duration{ weeks: weeks, days: days, hours: hours, minutes: minutes, seconds: seconds }
}

fn prettytime(input: Vec<String>) -> Result<String, String> {
    if input.len() < 1 { return Err("No input".to_string()); }

    let ref args1: String = input[0];
    let seconds: u64 = try!(args1.parse().or(Err("Not an integer".to_string())));

    let duration = sec2duration(seconds);

    Ok(format!("{}", duration))
}

fn main() {
    let args: Vec<_> = env::args().skip(1).collect();
    match prettytime(args) {
        Ok(s) => { println!("{}", s); },
        Err(s) => { println!("{}", s); }
    }
}

#[test]
fn test_print_duration() {
    assert_eq!("", format!("{}", Duration::new()));
    assert_eq!("1s", format!("{}", Duration::new().set_seconds(1)));
    assert_eq!("1m00s", format!("{}", Duration::new().set_minutes(1)));
    assert_eq!("1m03s", format!("{}", Duration::new().set_minutes(1).set_seconds(3)));
    assert_eq!("1hr00m00s", format!("{}", Duration::new().set_hours(1)));
    assert_eq!("1dy0hr00m00s", format!("{}", Duration::new().set_days(1)));
    assert_eq!("1wk0dy0hr00m00s", format!("{}", Duration::new().set_weeks(1)));
}
<|endoftext|>


<commit_before>// Copyright 2015-2016 Intecture Developers. See the COPYRIGHT file at the
// top-level directory of this distribution and at
// https://intecture.io/COPYRIGHT.
//
// Licensed under the Mozilla Public License 2.0 <LICENSE or
// https://www.tldrlegal.com/l/mpl-2.0>. This file may not be copied,
// modified, or distributed except according to those terms.

extern crate czmq;
extern crate docopt;
extern crate inapi;
extern crate rustc_serialize;
#[cfg(test)]
extern crate tempdir;
extern crate time;
extern crate zdaemon;

mod auth;
mod cert;
mod error;
mod language;
mod payload;
mod project;

use auth::Auth;
use docopt::Docopt;
use error::Result;
use language::language_from_str;
use payload::Payload;
use project::Project;
use std::{env, io};
use std::path::Path;
use std::process::exit;

const API_VERSION: &'static str = "{ git = \"https://github.com/intecture/api\" }";
const VERSION: &'static str = "0.2.1";

static USAGE: &'static str = "
Intecture CLI.

Usage:
  incli run [<arg>...]
  incli project init <name> <lang>
  incli payload init <name> <lang>
  incli payload build [<names>...]
  incli host (add | delete | bootstrap) [(-s | --silent)] <hostname>
  incli host list
  incli user (add | delete) [(-s | --silent)] <username>
  incli user list
  incli (-h | --help)
  incli --version

Options:
  -h --help     Show this screen.
  -s --silent   Save private key instead of printing it.
  -v --verbose  Verbose output.
  --version     Show version.
";

#[derive(Debug, RustcDecodable)]
struct Args {
    cmd_add: bool,
    cmd_bootstrap: bool,
    cmd_build: bool,
    cmd_delete: bool,
    cmd_host: bool,
    cmd_init: bool,
    cmd_list: bool,
    cmd_payload: bool,
    cmd_project: bool,
    cmd_run: bool,
    cmd_user: bool,
    flag_h: bool,
    flag_help: bool,
    flag_s: bool,
    flag_silent: bool,
    flag_v: bool,
    flag_verbose: bool,
    flag_version: bool,
    arg_arg: Vec<String>,
    arg_hostname: String,
    arg_lang: String,
    arg_name: String,
    arg_names: Option<Vec<String>>,
    arg_username: String,
}

fn main() {
    let args: Args = Docopt::new(USAGE)
        .and_then(|d| d.decode())
        .unwrap_or_else(|e| e.exit());

    if let Err(e) = run(&args) {
        println!("{}", e);

        if args.flag_v || args.flag_verbose {
            println!("{:?}", e);
        }

        exit(1);
    }
}

fn run(args: &Args) -> Result<()> {
    if args.flag_version {
        println!("{}", VERSION);
    }
    else if args.cmd_run {
        let project = try!(Project::load(&mut env::current_dir().unwrap()));
        let args_deref: Vec<&str> = args.arg_arg.iter().map(AsRef::as_ref).collect();
        try!(project.run(&args_deref));
    }
    else if args.cmd_project && args.cmd_init {
        try!(Project::create(&Path::new(&args.arg_name), try!(language_from_str(&args.arg_lang))));
    }
    else if args.cmd_payload {
        if args.cmd_init {
            try!(Payload::create(&Path::new(&args.arg_name), try!(language_from_str(&args.arg_lang))));
        }
        else if args.cmd_build {
            let payloads = if let Some(ref names) = args.arg_names {
                let n: Vec<&str> = names.iter().map(|n| &**n).collect();
                try!(Payload::find(".", Some(&*n)))
            } else {
                try!(Payload::find(".", None))
            };
            for payload in payloads {
                try!(payload.build());
            }
        }
    }
    else if args.cmd_host || args.cmd_user {
        let cert_type = if args.cmd_host { "host" } else { "user" };
        let name = if args.cmd_host { &args.arg_hostname } else { &args.arg_username };

        let auth = try!(Auth::new(&env::current_dir().unwrap()));

        if args.cmd_add {
            let cert = try!(auth.add(cert_type, name));
            if args.flag_s || args.flag_silent {
                try!(cert.save_secret(&format!("{}.crt", name)));
            } else {
                println!("Please distribute this certificate securely.

------------------------COPY BELOW THIS LINE-------------------------
{}
------------------------COPY ABOVE THIS LINE-------------------------", cert.secret());
            }
        }
        else if args.cmd_delete {
            if args.flag_s || args.flag_silent {
                try!(auth.delete(name));
            } else {
                println!("Are you sure you want to delete this certificate?");
                loop {
                    println!("Please enter [y/n]: ");
                    let mut input = String::new();
                    match io::stdin().read_line(&mut input) {
                        Ok(_) => match { input.as_ref() as &str }.trim() {
                            "y" => {
                                try!(auth.delete(name));
                                break;
                            },
                            "n" => break,
                            _ => (),
                        },
                        Err(e) => {
                            println!("Stdin error: {}", e);
                            exit(1);
                        },
                    }
                }
            }
        }
        else if args.cmd_list {
            let names = try!(auth.list(cert_type));

            for name in names {
                println!("{}", name);
            }
        }
        else if args.cmd_bootstrap && args.cmd_host {
            unimplemented!();
        }
    }

    Ok(())
}
<commit_msg>Fix bug where run() exit status was being ignored<commit_after>// Copyright 2015-2016 Intecture Developers. See the COPYRIGHT file at the
// top-level directory of this distribution and at
// https://intecture.io/COPYRIGHT.
//
// Licensed under the Mozilla Public License 2.0 <LICENSE or
// https://www.tldrlegal.com/l/mpl-2.0>. This file may not be copied,
// modified, or distributed except according to those terms.

extern crate czmq;
extern crate docopt;
extern crate inapi;
extern crate rustc_serialize;
#[cfg(test)]
extern crate tempdir;
extern crate time;
extern crate zdaemon;

mod auth;
mod cert;
mod error;
mod language;
mod payload;
mod project;

use auth::Auth;
use docopt::Docopt;
use error::Result;
use language::language_from_str;
use payload::Payload;
use project::Project;
use std::{env, io};
use std::path::Path;
use std::process::exit;

const API_VERSION: &'static str = "{ git = \"https://github.com/intecture/api\" }";
const VERSION: &'static str = "0.2.1";

static USAGE: &'static str = "
Intecture CLI.

Usage:
  incli run [<arg>...]
  incli project init <name> <lang>
  incli payload init <name> <lang>
  incli payload build [<names>...]
  incli host (add | delete | bootstrap) [(-s | --silent)] <hostname>
  incli host list
  incli user (add | delete) [(-s | --silent)] <username>
  incli user list
  incli (-h | --help)
  incli --version

Options:
  -h --help     Show this screen.
  -s --silent   Save private key instead of printing it.
  -v --verbose  Verbose output.
  --version     Show version.
";

#[derive(Debug, RustcDecodable)]
struct Args {
    cmd_add: bool,
    cmd_bootstrap: bool,
    cmd_build: bool,
    cmd_delete: bool,
    cmd_host: bool,
    cmd_init: bool,
    cmd_list: bool,
    cmd_payload: bool,
    cmd_project: bool,
    cmd_run: bool,
    cmd_user: bool,
    flag_h: bool,
    flag_help: bool,
    flag_s: bool,
    flag_silent: bool,
    flag_v: bool,
    flag_verbose: bool,
    flag_version: bool,
    arg_arg: Vec<String>,
    arg_hostname: String,
    arg_lang: String,
    arg_name: String,
    arg_names: Option<Vec<String>>,
    arg_username: String,
}

fn main() {
    let args: Args = Docopt::new(USAGE)
        .and_then(|d| d.decode())
        .unwrap_or_else(|e| e.exit());

    if let Err(e) = run(&args) {
        println!("{}", e);

        if args.flag_v || args.flag_verbose {
            println!("{:?}", e);
        }

        exit(1);
    }
}

fn run(args: &Args) -> Result<()> {
    if args.flag_version {
        println!("{}", VERSION);
    }
    else if args.cmd_run {
        let project = try!(Project::load(&mut env::current_dir().unwrap()));
        let args_deref: Vec<&str> = args.arg_arg.iter().map(AsRef::as_ref).collect();
        let status = try!(project.run(&args_deref));

        if !status.success() {
            exit(status.code().unwrap_or(1));
        }
    }
    else if args.cmd_project && args.cmd_init {
        try!(Project::create(&Path::new(&args.arg_name), try!(language_from_str(&args.arg_lang))));
    }
    else if args.cmd_payload {
        if args.cmd_init {
            try!(Payload::create(&Path::new(&args.arg_name), try!(language_from_str(&args.arg_lang))));
        }
        else if args.cmd_build {
            let payloads = if let Some(ref names) = args.arg_names {
                let n: Vec<&str> = names.iter().map(|n| &**n).collect();
                try!(Payload::find(".", Some(&*n)))
            } else {
                try!(Payload::find(".", None))
            };
            for payload in payloads {
                try!(payload.build());
            }
        }
    }
    else if args.cmd_host || args.cmd_user {
        let cert_type = if args.cmd_host { "host" } else { "user" };
        let name = if args.cmd_host { &args.arg_hostname } else { &args.arg_username };

        let auth = try!(Auth::new(&env::current_dir().unwrap()));

        if args.cmd_add {
            let cert = try!(auth.add(cert_type, name));
            if args.flag_s || args.flag_silent {
                try!(cert.save_secret(&format!("{}.crt", name)));
            } else {
                println!("Please distribute this certificate securely.

------------------------COPY BELOW THIS LINE-------------------------
{}
------------------------COPY ABOVE THIS LINE-------------------------", cert.secret());
            }
        }
        else if args.cmd_delete {
            if args.flag_s || args.flag_silent {
                try!(auth.delete(name));
            } else {
                println!("Are you sure you want to delete this certificate?");
                loop {
                    println!("Please enter [y/n]: ");
                    let mut input = String::new();
                    match io::stdin().read_line(&mut input) {
                        Ok(_) => match { input.as_ref() as &str }.trim() {
                            "y" => {
                                try!(auth.delete(name));
                                break;
                            },
                            "n" => break,
                            _ => (),
                        },
                        Err(e) => {
                            println!("Stdin error: {}", e);
                            exit(1);
                        },
                    }
                }
            }
        }
        else if args.cmd_list {
            let names = try!(auth.list(cert_type));

            for name in names {
                println!("{}", name);
            }
        }
        else if args.cmd_bootstrap && args.cmd_host {
            unimplemented!();
        }
    }

    Ok(())
}
<|endoftext|>


<commit_before>use std::collections::HashMap;
use std::fmt;
use std::io::{self, Write};
use std::process::{Command, ExitStatus};

extern crate itertools;
use itertools::Itertools;

// TODO(tsion): Use the readline library.
fn prompt(line: &mut String) -> io::Result<usize> {
    let current_dir = try!(std::env::current_dir());
    print!("{}> ", current_dir.display());
    try!(io::stdout().flush());
    io::stdin().read_line(line)
}

#[derive(Clone, Debug, Eq, PartialEq)]
enum Expr {
    Text(String),
}

#[derive(Clone, Debug, Eq, PartialEq)]
enum Ast {
    Empty,
    Call { command: String, args: Vec<Vec<Expr>> }
}

#[derive(Clone, Debug, Eq, PartialEq)]
enum Token {
    Newline,
    Whitespace,
    Text(String),
}

#[derive(Clone)]
struct Lexer<'src> {
    source: &'src str,
    position: usize,
}

#[derive(Clone, Debug, Eq, PartialEq)]
enum ParseError {
    UnclosedDelimiter(char),
    UnexpectedChar(char),
    UnexpectedEnd,
}

type ParseResult<T> = Result<T, ParseError>;

impl fmt::Display for ParseError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            ParseError::UnclosedDelimiter(c) => write!(f, "unclosed delimiter: '{}'", c),
            ParseError::UnexpectedChar(c) => write!(f, "unexpected character: '{}'", c),
            ParseError::UnexpectedEnd => write!(f, "unexpected end of input"),
        }
    }
}

impl<'src> Lexer<'src> {
    fn new(source: &str) -> Lexer {
        Lexer {
            source: source,
            position: 0,
        }
    }

    fn read_char(&mut self) -> Option<char> {
        let opt_c = self.source[self.position..].chars().next();

        if let Some(c) = opt_c {
            self.position += c.len_utf8();
        }

        opt_c
    }

    /// Step backwards one `char` in the input. Must not be called more times than `read_char` has
    /// been called.
    fn unread_char(&mut self) {
        assert!(self.position != 0);
        let (prev_pos, _) = self.source[..self.position].char_indices().next_back().unwrap();
        self.position = prev_pos;
    }

    fn is_whitespace(c: char) -> bool {
        c == ' ' || c == '\t'
    }

    fn is_unquoted_text(c: char) -> bool {
        match c {
            'a'...'z' | 'A'...'Z' | '0'...'9' | '-' | '+' | '/' | '_' | '.' | ',' => true,
            _ => false,
        }
    }

    fn skip_while<F>(&mut self, mut predicate: F) where F: FnMut(char) -> bool {
        while let Some(c) = self.read_char() {
            if !predicate(c) {
                self.unread_char();
                break;
            }
        }
    }

    fn lex_whitespace(&mut self) -> ParseResult<Token> {
        self.skip_while(Lexer::is_whitespace);
        Ok(Token::Whitespace)
    }

    fn lex_unquoted_text(&mut self) -> ParseResult<Token> {
        let start = self.position;
        self.skip_while(Lexer::is_unquoted_text);
        let end = self.position;

        let text = String::from(&self.source[start..end]);
        Ok(Token::Text(text))
    }

    fn lex_double_quoted_text(&mut self) -> ParseResult<Token> {
        let mut text = String::new();

        while let Some(c) = self.read_char() {
            match c {
                '"'  => return Ok(Token::Text(text)),
                '\\' => try!(self.lex_double_quote_escape(&mut text)),
                c => text.push(c),
            };
        }

        Err(ParseError::UnclosedDelimiter('"'))
    }

    fn lex_double_quote_escape(&mut self, text: &mut String) -> ParseResult<()> {
        let escaped = try!(self.read_char().ok_or(ParseError::UnexpectedEnd));

        match escaped {
            '\\' | '"' => text.push(escaped),
            c => {
                text.push('\\');
                text.push(c);
            }
        }

        Ok(())
    }
}

impl<'src> Iterator for Lexer<'src> {
    type Item = ParseResult<Token>;

    fn next(&mut self) -> Option<ParseResult<Token>> {
        self.read_char().map(|c| {
            match c {
                c if Lexer::is_whitespace(c)    => self.lex_whitespace(),
                c if Lexer::is_unquoted_text(c) => {
                    self.unread_char();
                    self.lex_unquoted_text()
                },
                '\r' | '\n'                     => Ok(Token::Newline),
                '"'                             => self.lex_double_quoted_text(),
                c                               => Err(ParseError::UnexpectedChar(c)),
            }
        })
    }
}

#[derive(Clone)]
struct Parser<'src> {
    lexer: Lexer<'src>,
}

impl<'src> Parser<'src> {
    fn new(input: &str) -> Parser {
        Parser { lexer: Lexer::new(input) }
    }

    fn parse(&mut self) -> ParseResult<Ast> {
        if let Some(token_result) = self.lexer.next() {
            let token = try!(token_result);
            match token {
                Token::Whitespace | Token::Newline => self.parse(),
                Token::Text(command) => self.parse_call(command),
            }
        } else {
            Ok(Ast::Empty)
        }
    }

    fn parse_call(&mut self, command: String) -> ParseResult<Ast> {
        let mut args = vec![];
        let mut current_arg = vec![];

        for token_result in &mut self.lexer {
            let token = try!(token_result);
            match token {
                Token::Newline => {
                    if !current_arg.is_empty() {
                        args.push(current_arg);
                    }
                    break;
                },

                Token::Whitespace => {
                    if !current_arg.is_empty() {
                        args.push(current_arg);
                        current_arg = vec![];
                    }
                },

                Token::Text(text) => {
                    current_arg.push(Expr::Text(text));
                },
            }
        }

        Ok(Ast::Call { command: command, args: args })
    }
}

struct Builtin {
    name: &'static str,
    min_args: usize,
    max_args: usize,
    func: fn(&[String]) -> i32,
}

fn result_to_exit_code(cmd: &'static str, result: io::Result<()>) -> i32 {
    match result {
        Ok(()) => 0,
        Err(e) => {
            writeln!(&mut io::stderr(), "shroom: {}: {}", cmd, e).unwrap();
            1
        },
    }
}

fn builtin_cd(args: &[String]) -> i32 {
    if let Some(path) = args.get(0) {
        result_to_exit_code("cd", std::env::set_current_dir(path))
    } else if let Some(home) = std::env::home_dir() {
        result_to_exit_code("cd", std::env::set_current_dir(home))
    } else {
        writeln!(&mut io::stderr(), "shroom: cd: couldn't find home dir").unwrap();
        1
    }
}

fn builtin_exit(args: &[String]) -> i32 {
    if let Some(exit_code_str) = args.get(0) {
        match exit_code_str.parse() {
            Ok(exit_code) => std::process::exit(exit_code),
            Err(e) => {
                writeln!(&mut io::stderr(), "shroom: exit: can't parse exit code: {}", e).unwrap();
                1
            },
        }
    } else {
        std::process::exit(0);
    }
}

fn execute(ast: &Ast) -> i32 {
    let mut builtins = HashMap::new();

    builtins.insert("cd", Builtin {
        name: "cd",
        min_args: 0,
        max_args: 1,
        func: builtin_cd,
    });

    builtins.insert("exit", Builtin {
        name: "exit",
        min_args: 0,
        max_args: 1,
        func: builtin_exit,
    });

    match *ast {
        Ast::Empty => 0,

        Ast::Call { ref command, ref args } => {
            // Evaluate argument expressions.
            let evaluated_args: Vec<String> = args.iter().map(|arg| {
                arg.iter().map(|expr| {
                    match *expr {
                        Expr::Text(ref text) => text,
                    }
                }).join("")
            }).collect();

            if let Some(builtin) = builtins.get(&command[..]) {
                if args.len() < builtin.min_args {
                    writeln!(&mut io::stderr(), "shroom: {}: not enough arguments",
                             builtin.name).unwrap();
                    1
                } else if args.len() > builtin.max_args {
                    writeln!(&mut io::stderr(), "shroom: {}: too many arguments",
                             builtin.name).unwrap();
                    1
                } else {
                    (builtin.func)(&evaluated_args)
                }
            } else {
                match Command::new(command).args(&evaluated_args).status() {
                    Ok(exit_status) => {
                        #[cfg(unix)]
                        fn exit_signal(exit_status: &ExitStatus) -> Option<i32> {
                            use std::os::unix::process::ExitStatusExt;
                            exit_status.signal()
                        }

                        #[cfg(not(unix))]
                        fn exit_signal(_exit_status: &ExitStatus) -> Option<i32> {
                            None
                        }

                        if let Some(code) = exit_status.code() {
                            code
                        } else if let Some(signal) = exit_signal(&exit_status) {
                            128 + signal
                        } else {
                            127
                        }
                    },

                    Err(e) => {
                        writeln!(&mut io::stderr(), "shroom: {}: {}", command, e).unwrap();
                        127
                    },
                }
            }
        },
    }
}

fn main() {
    let mut line = String::new();
    loop {
        prompt(&mut line).unwrap();

        match Parser::new(&line).parse() {
            Ok(ast) => {
                let exit_code = execute(&ast);
                if exit_code != 0 {
                    println!("shroom: exit code: {}", exit_code);
                }
            },

            Err(parse_error) => {
                println!("shroom: parse error: {}", parse_error);
            },
        }

        line.clear();
    }
}
<commit_msg>Simplify errors until we have source spans.<commit_after>use std::collections::HashMap;
use std::{error, fmt};
use std::io::{self, Write};
use std::process::{Command, ExitStatus};

extern crate itertools;
use itertools::Itertools;

// TODO(tsion): Use the readline library.
fn prompt(line: &mut String) -> io::Result<usize> {
    let current_dir = try!(std::env::current_dir());
    print!("{}> ", current_dir.display());
    try!(io::stdout().flush());
    io::stdin().read_line(line)
}

#[derive(Clone, Debug, Eq, PartialEq)]
enum Expr {
    Text(String),
}

#[derive(Clone, Debug, Eq, PartialEq)]
enum Ast {
    Empty,
    Call { command: String, args: Vec<Vec<Expr>> }
}

#[derive(Clone, Debug, Eq, PartialEq)]
enum Token {
    Newline,
    Whitespace,
    Text(String),
}

#[derive(Clone)]
struct Lexer<'src> {
    source: &'src str,
    position: usize,
}

#[derive(Clone, Debug, Eq, PartialEq)]
enum ParseError {
    UnclosedDelimiter,
    UnexpectedChar,
    UnexpectedEnd,
}

type ParseResult<T> = Result<T, ParseError>;

impl error::Error for ParseError {
    fn description(&self) -> &str {
        match *self {
            ParseError::UnclosedDelimiter => "unclosed delimiter",
            ParseError::UnexpectedChar    => "unexpected character",
            ParseError::UnexpectedEnd     => "unexpected end of input",
        }
    }
}

impl fmt::Display for ParseError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}", error::Error::description(self))
    }
}

impl<'src> Lexer<'src> {
    fn new(source: &str) -> Lexer {
        Lexer {
            source: source,
            position: 0,
        }
    }

    fn read_char(&mut self) -> Option<char> {
        let opt_c = self.source[self.position..].chars().next();

        if let Some(c) = opt_c {
            self.position += c.len_utf8();
        }

        opt_c
    }

    /// Step backwards one `char` in the input. Must not be called more times than `read_char` has
    /// been called.
    fn unread_char(&mut self) {
        assert!(self.position != 0);
        let (prev_pos, _) = self.source[..self.position].char_indices().next_back().unwrap();
        self.position = prev_pos;
    }

    fn is_whitespace(c: char) -> bool {
        c == ' ' || c == '\t'
    }

    fn is_unquoted_text(c: char) -> bool {
        match c {
            'a'...'z' | 'A'...'Z' | '0'...'9' | '-' | '+' | '/' | '_' | '.' | ',' => true,
            _ => false,
        }
    }

    fn skip_while<F>(&mut self, mut predicate: F) where F: FnMut(char) -> bool {
        while let Some(c) = self.read_char() {
            if !predicate(c) {
                self.unread_char();
                break;
            }
        }
    }

    fn lex_whitespace(&mut self) -> ParseResult<Token> {
        self.skip_while(Lexer::is_whitespace);
        Ok(Token::Whitespace)
    }

    fn lex_unquoted_text(&mut self) -> ParseResult<Token> {
        let start = self.position;
        self.skip_while(Lexer::is_unquoted_text);
        let end = self.position;

        let text = String::from(&self.source[start..end]);
        Ok(Token::Text(text))
    }

    fn lex_double_quoted_text(&mut self) -> ParseResult<Token> {
        let mut text = String::new();

        while let Some(c) = self.read_char() {
            match c {
                '"'  => return Ok(Token::Text(text)),
                '\\' => try!(self.lex_double_quote_escape(&mut text)),
                c => text.push(c),
            };
        }

        Err(ParseError::UnclosedDelimiter)
    }

    fn lex_double_quote_escape(&mut self, text: &mut String) -> ParseResult<()> {
        let escaped = try!(self.read_char().ok_or(ParseError::UnexpectedEnd));

        match escaped {
            '\\' | '"' => text.push(escaped),
            c => {
                text.push('\\');
                text.push(c);
            }
        }

        Ok(())
    }
}

impl<'src> Iterator for Lexer<'src> {
    type Item = ParseResult<Token>;

    fn next(&mut self) -> Option<ParseResult<Token>> {
        self.read_char().map(|c| {
            match c {
                c if Lexer::is_whitespace(c)    => self.lex_whitespace(),
                c if Lexer::is_unquoted_text(c) => {
                    self.unread_char();
                    self.lex_unquoted_text()
                },
                '\r' | '\n'                     => Ok(Token::Newline),
                '"'                             => self.lex_double_quoted_text(),
                _                               => Err(ParseError::UnexpectedChar),
            }
        })
    }
}

#[derive(Clone)]
struct Parser<'src> {
    lexer: Lexer<'src>,
}

impl<'src> Parser<'src> {
    fn new(input: &str) -> Parser {
        Parser { lexer: Lexer::new(input) }
    }

    fn parse(&mut self) -> ParseResult<Ast> {
        if let Some(token_result) = self.lexer.next() {
            let token = try!(token_result);
            match token {
                Token::Whitespace | Token::Newline => self.parse(),
                Token::Text(command) => self.parse_call(command),
            }
        } else {
            Ok(Ast::Empty)
        }
    }

    fn parse_call(&mut self, command: String) -> ParseResult<Ast> {
        let mut args = vec![];
        let mut current_arg = vec![];

        for token_result in &mut self.lexer {
            let token = try!(token_result);
            match token {
                Token::Newline => {
                    if !current_arg.is_empty() {
                        args.push(current_arg);
                    }
                    break;
                },

                Token::Whitespace => {
                    if !current_arg.is_empty() {
                        args.push(current_arg);
                        current_arg = vec![];
                    }
                },

                Token::Text(text) => {
                    current_arg.push(Expr::Text(text));
                },
            }
        }

        Ok(Ast::Call { command: command, args: args })
    }
}

struct Builtin {
    name: &'static str,
    min_args: usize,
    max_args: usize,
    func: fn(&[String]) -> i32,
}

fn result_to_exit_code(cmd: &'static str, result: io::Result<()>) -> i32 {
    match result {
        Ok(()) => 0,
        Err(e) => {
            writeln!(&mut io::stderr(), "shroom: {}: {}", cmd, e).unwrap();
            1
        },
    }
}

fn builtin_cd(args: &[String]) -> i32 {
    if let Some(path) = args.get(0) {
        result_to_exit_code("cd", std::env::set_current_dir(path))
    } else if let Some(home) = std::env::home_dir() {
        result_to_exit_code("cd", std::env::set_current_dir(home))
    } else {
        writeln!(&mut io::stderr(), "shroom: cd: couldn't find home dir").unwrap();
        1
    }
}

fn builtin_exit(args: &[String]) -> i32 {
    if let Some(exit_code_str) = args.get(0) {
        match exit_code_str.parse() {
            Ok(exit_code) => std::process::exit(exit_code),
            Err(e) => {
                writeln!(&mut io::stderr(), "shroom: exit: can't parse exit code: {}", e).unwrap();
                1
            },
        }
    } else {
        std::process::exit(0);
    }
}

fn execute(ast: &Ast) -> i32 {
    let mut builtins = HashMap::new();

    builtins.insert("cd", Builtin {
        name: "cd",
        min_args: 0,
        max_args: 1,
        func: builtin_cd,
    });

    builtins.insert("exit", Builtin {
        name: "exit",
        min_args: 0,
        max_args: 1,
        func: builtin_exit,
    });

    match *ast {
        Ast::Empty => 0,

        Ast::Call { ref command, ref args } => {
            // Evaluate argument expressions.
            let evaluated_args: Vec<String> = args.iter().map(|arg| {
                arg.iter().map(|expr| {
                    match *expr {
                        Expr::Text(ref text) => text,
                    }
                }).join("")
            }).collect();

            if let Some(builtin) = builtins.get(&command[..]) {
                if args.len() < builtin.min_args {
                    writeln!(&mut io::stderr(), "shroom: {}: not enough arguments",
                             builtin.name).unwrap();
                    1
                } else if args.len() > builtin.max_args {
                    writeln!(&mut io::stderr(), "shroom: {}: too many arguments",
                             builtin.name).unwrap();
                    1
                } else {
                    (builtin.func)(&evaluated_args)
                }
            } else {
                match Command::new(command).args(&evaluated_args).status() {
                    Ok(exit_status) => {
                        #[cfg(unix)]
                        fn exit_signal(exit_status: &ExitStatus) -> Option<i32> {
                            use std::os::unix::process::ExitStatusExt;
                            exit_status.signal()
                        }

                        #[cfg(not(unix))]
                        fn exit_signal(_exit_status: &ExitStatus) -> Option<i32> {
                            None
                        }

                        if let Some(code) = exit_status.code() {
                            code
                        } else if let Some(signal) = exit_signal(&exit_status) {
                            128 + signal
                        } else {
                            127
                        }
                    },

                    Err(e) => {
                        writeln!(&mut io::stderr(), "shroom: {}: {}", command, e).unwrap();
                        127
                    },
                }
            }
        },
    }
}

fn main() {
    let mut line = String::new();
    loop {
        prompt(&mut line).unwrap();

        match Parser::new(&line).parse() {
            Ok(ast) => {
                let exit_code = execute(&ast);
                if exit_code != 0 {
                    println!("shroom: exit code: {}", exit_code);
                }
            },

            Err(parse_error) => {
                println!("shroom: parse error: {}", parse_error);
            },
        }

        line.clear();
    }
}
<|endoftext|>


<commit_before>extern crate rustc_serialize;
use rustc_serialize::json;

use std::fmt;
use std::env;

use std::fs::File;
use std::io::Read;

use std::thread;
use std::sync::{Mutex, Arc};
use std::process::Command;

extern crate ansi_term;
use ansi_term::Colour;

struct WorkConf {
    project: String,
    operate: String,
    head:    String,
}

impl fmt::Debug for WorkConf {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "WorkConf:{}\"project\": {}, \"operate\": {}, \"head\": {}{}",
            "{", self.project, self.operate, self.head, "}")
    }
}

// Automatically generate `RustcDecodable` and `RustcEncodable` trait
// implementations
#[derive(RustcDecodable, RustcEncodable)]
struct DeployConf {
    user: String,
    path: String,
    hosts_conf: Vec<String>,
}

fn usage(argv_0: &String) {
    println!("\n{}", Colour::Cyan.bold().paint("-----USAGE----"));
    println!("{} {} {}             {}",
        Colour::Green.bold().paint(argv_0.to_string()),
        Colour::Blue.bold().paint("project"),
        Colour::Yellow.bold().paint("deploy"),
        Colour::Red.paint("deploy project with latest <head>."));
    println!("{} {} {} {}    {}\n",
        Colour::Green.bold().paint(argv_0.to_string()),
        Colour::Blue.bold().paint("project"),
        Colour::Yellow.bold().paint("rollback"),
        Colour::Purple.bold().paint("<head>"),
        Colour::Red.paint("rollback with <head>."));
    std::process::exit(0);
}

static DEBUG: bool = false;

fn main() {
    let args: Vec<_> = env::args().collect();
    let argc = args.len();

    if argc < 3 {
        usage(&args[0]);
    }

    // 处理命令行参数
    let project = args[1].to_string();
    let operate = args[2].to_string();
    if ("deploy".to_string() != operate && "rollback".to_string() != operate) || ("rollback".to_string() == operate && argc < 4) {
        usage(&args[0]);
    }

    let head = if argc > 3 { args[3].to_string() } else { "".to_string() };

    let work_conf = WorkConf{
        project: project,
        operate: operate,
        head:    head,
    };
    if DEBUG { println!("{:?}", work_conf); }

    let config_filename = format!("./conf/{}.json", work_conf.project);
    if DEBUG { println!("config_filename: {}", config_filename); }

    let mut data = String::new();
    let mut f = File::open(config_filename)
        .ok()
        .expect("Can NOT open file.");
    f.read_to_string(&mut data)
        .ok()
        .expect("Can NOT read cofing file.");
    if DEBUG { println!("deploy_conf: {}", data)}
    let deploy_conf: DeployConf = json::decode(&data)
        .ok()
        .expect("Can NOT parse JSON config data.");
    if DEBUG { println!("JSON: {}", json::encode(&deploy_conf).unwrap()); }

    let mut hosts_conf = Vec::new();
    let hosts_len = deploy_conf.hosts_conf.len();
    for index in 0 .. hosts_len {
        hosts_conf.push(deploy_conf.hosts_conf[index].clone());
    }
    let mutex_ct = Arc::new(Mutex::new(vec![1]));

    println!("          ===== {} ======\n", Colour::Blue.bold().paint(work_conf.project.to_string()));

    let handles: Vec<_> = hosts_conf.into_iter().map(|host| {
        let user = deploy_conf.user.clone();
        let path = deploy_conf.path.clone();
        let operate = work_conf.operate.clone();
        let head    = work_conf.head.clone();
        let mutex_ct= mutex_ct.clone();
        thread::spawn(move || {
            let cmd = if "deploy".to_string() == operate {
                format!("ssh {}@{} \"cd {} && git pull && git log -1 | awk '{{if (\\$1 ~/commit/) {{print \\$2}}}}' 2>&1\"",
                user, host, path)
            } else {
                format!("ssh {}@{} \"cd {} && git reset --hard {} && git log -1 | awk '{{if (\\$1 ~/commit/) {{print \\$2}}}}' 2>&1\"",
                user, host, path, head)
            };
            if DEBUG { println!("CMD: {}", cmd); }
            let output = Command::new("sh")
                .arg("-c")
                .arg(cmd)
                .output()
                .unwrap_or_else(|e| { panic!("failed to execute process: {}", e) });

            let user_at_host = format!("{}{}{}",
                Colour::Green.bold().paint(user.to_string()),
                Colour::Red.bold().paint("@"),
                Colour::Cyan.bold().paint(host.to_string()));
            // 解决多线程穿插输出的问题
            let mut output_buf = "".to_string();
            output_buf = output_buf + &(format!("--- {} {} for {} ---\n",
                Colour::Cyan.bold().paint("START"),
                Colour::Purple.bold().paint(operate.to_string()), user_at_host));
            if Some(0) == output.status.code() {
                output_buf = output_buf + &(format!("{}\n", String::from_utf8_lossy(&output.stdout)));
                output_buf = output_buf + &(format!("{} {} for {}\n",
                    Colour::Purple.bold().paint(operate.to_string()),
                    Colour::Green.bold().paint("SUCCESS"),
                    user_at_host));
            } else {
                output_buf = output_buf + &(format!("{} {}\n", Colour::Red.bold().paint("stderr:"),String::from_utf8_lossy(&output.stderr)));
                output_buf = output_buf + &(format!("{} {} for {}\n",
                    Colour::Purple.bold().paint(operate.to_string()),
                    Colour::Red.bold().paint("FAIL!"),
                    user_at_host));
            }
            output_buf = output_buf + &(format!("--- {} ---\n", Colour::Cyan.bold().paint("END")));

            {
                let _ct = mutex_ct.lock().unwrap();
                if DEBUG { println!("status: {:?}", output.status.code()); }
                println!("{}", output_buf);
            }
        })
    }).collect();

    for h in handles {
        h.join().unwrap();
    }
}
<commit_msg>1. 简化代码书写; 2. 加入闪烁提示.<commit_after>extern crate rustc_serialize;
use rustc_serialize::json;

use std::fmt;
use std::env;

use std::fs::File;
use std::io::Read;

use std::thread;
use std::sync::{Mutex, Arc};
use std::process::Command;

extern crate ansi_term;
use ansi_term::Colour::{Red, Green, Yellow, Blue, Purple, Cyan};

struct WorkConf {
    project: String,
    operate: String,
    head:    String,
}

impl fmt::Debug for WorkConf {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "WorkConf:{}\"project\": {}, \"operate\": {}, \"head\": {}{}",
            "{", self.project, self.operate, self.head, "}")
    }
}

// Automatically generate `RustcDecodable` and `RustcEncodable` trait
// implementations
#[derive(RustcDecodable, RustcEncodable)]
struct DeployConf {
    user: String,
    path: String,
    hosts_conf: Vec<String>,
}

fn usage(argv_0: &String) {
    println!("\n{}", Cyan.bold().paint("-----USAGE----"));
    println!("{} {} {}             {}",
        Green.bold().paint(argv_0.to_string()),
        Blue.bold().paint("project"),
        Yellow.bold().paint("deploy"),
        Red.paint("deploy project with latest <head>."));
    println!("{} {} {} {}    {}\n",
        Green.bold().paint(argv_0.to_string()),
        Blue.bold().paint("project"),
        Yellow.bold().paint("rollback"),
        Purple.bold().paint("<head>"),
        Red.paint("rollback with <head>."));
    std::process::exit(0);
}

static DEBUG: bool = false;

fn main() {
    let args: Vec<_> = env::args().collect();
    let argc = args.len();

    if argc < 3 {
        usage(&args[0]);
    }

    // 处理命令行参数
    let project = args[1].to_string();
    let operate = args[2].to_string();
    if ("deploy".to_string() != operate && "rollback".to_string() != operate) || ("rollback".to_string() == operate && argc < 4) {
        usage(&args[0]);
    }

    let head = if argc > 3 { args[3].to_string() } else { "".to_string() };

    let work_conf = WorkConf{
        project: project,
        operate: operate,
        head:    head,
    };
    if DEBUG { println!("{:?}", work_conf); }

    let config_filename = format!("./conf/{}.json", work_conf.project);
    if DEBUG { println!("config_filename: {}", config_filename); }

    let mut data = String::new();
    let mut f = File::open(config_filename)
        .ok()
        .expect("Can NOT open file.");
    f.read_to_string(&mut data)
        .ok()
        .expect("Can NOT read cofing file.");
    if DEBUG { println!("deploy_conf: {}", data)}
    let deploy_conf: DeployConf = json::decode(&data)
        .ok()
        .expect("Can NOT parse JSON config data.");
    if DEBUG { println!("JSON: {}", json::encode(&deploy_conf).unwrap()); }

    let mut hosts_conf = Vec::new();
    let hosts_len = deploy_conf.hosts_conf.len();
    for index in 0 .. hosts_len {
        hosts_conf.push(deploy_conf.hosts_conf[index].clone());
    }
    let mutex_ct = Arc::new(Mutex::new(vec![1]));

    println!("          ====== {} ======\n", Blue.bold().paint(work_conf.project.to_string()));

    let handles: Vec<_> = hosts_conf.into_iter().map(|host| {
        let user = deploy_conf.user.clone();
        let path = deploy_conf.path.clone();
        let operate = work_conf.operate.clone();
        let head    = work_conf.head.clone();
        let mutex_ct= mutex_ct.clone();
        thread::spawn(move || {
            let cmd = if "deploy".to_string() == operate {
                format!("ssh {}@{} \"cd {} && git pull && git log -1 | awk '{{if (\\$1 ~/commit/) {{print \\$2}}}}' 2>&1\"",
                user, host, path)
            } else {
                format!("ssh {}@{} \"cd {} && git reset --hard {} && git log -1 | awk '{{if (\\$1 ~/commit/) {{print \\$2}}}}' 2>&1\"",
                user, host, path, head)
            };
            if DEBUG { println!("CMD: {}", cmd); }
            let output = Command::new("sh")
                .arg("-c")
                .arg(cmd)
                .output()
                .unwrap_or_else(|e| { panic!("failed to execute process: {}", e) });

            let user_at_host = format!("{}{}{}",
                Green.bold().paint(user.to_string()),
                Red.bold().paint("@"),
                Cyan.bold().paint(host.to_string()));
            // 解决多线程穿插输出的问题
            let mut output_buf = "".to_string();
            output_buf = output_buf + &(format!("--- {} {} for {} ---\n",
                Cyan.bold().paint("START"),
                Purple.bold().paint(operate.to_string()), user_at_host));
            if Some(0) == output.status.code() {
                output_buf = output_buf + &(format!("{}\n", String::from_utf8_lossy(&output.stdout)));
                output_buf = output_buf + &(format!("{} {} for {}\n",
                    Purple.bold().paint(operate.to_string()),
                    Green.bold().paint("SUCCESS"),
                    user_at_host));
            } else {
                output_buf = output_buf + &(format!("{} {}\n", Red.bold().blink().paint("stderr:"),String::from_utf8_lossy(&output.stderr)));
                output_buf = output_buf + &(format!("{} {} for {}\n",
                    Purple.bold().paint(operate.to_string()),
                    Red.bold().blink().paint("FAIL!"),
                    user_at_host));
            }
            output_buf = output_buf + &(format!("--- {} ---\n", Cyan.bold().paint("END")));

            {
                let _ct = mutex_ct.lock().unwrap();
                if DEBUG { println!("status: {:?}", output.status.code()); }
                println!("{}", output_buf);
            }
        })
    }).collect();

    for h in handles {
        h.join().unwrap();
    }
}
<|endoftext|>


<commit_before>use std::io;
use std::io::Write;
use std::io::stdout;

mod run_length_encoding;

fn main() {
    let mut input = String::new();

    println!("{:?}", vec![22;5]);

    print!("Enter text to encode: ");
    stdout().flush().unwrap();
    io::stdin().read_line(&mut input).unwrap();

    let compressed = run_length_encoding::encode(&input.trim());
    println!("{:?}", compressed);
    let decompressed = run_length_encoding::decode(compressed);
    println!("{:?}", decompressed);
}
<commit_msg>Remove useless line<commit_after>use std::io;
use std::io::Write;
use std::io::stdout;

mod run_length_encoding;

fn main() {
    let mut input = String::new();

    print!("Enter text to encode: ");
    stdout().flush().unwrap();
    io::stdin().read_line(&mut input).unwrap();

    let compressed = run_length_encoding::encode(&input.trim());
    println!("{:?}", compressed);
    let decompressed = run_length_encoding::decode(compressed);
    println!("{:?}", decompressed);
}
<|endoftext|>


<commit_before>extern crate log;
extern crate env_logger;
#[macro_use]
extern crate structopt;
extern crate failure;
extern crate mdblog;

use std::env;
use structopt::StructOpt;
use mdblog::{Mdblog, Result, print_error};

#[derive(StructOpt, Debug)]
#[structopt(name = "mdblog")]
/// static site generator from markdown files
enum Opt {
    #[structopt(name = "init")]
    /// Initialize the blog directory layout
    Init {
        /// the blog directory name
        name: String,
    },
    #[structopt(name = "build")]
    /// Build the blog static files
    Build,
    #[structopt(name = "serve")]
    /// Serve the blog, rebuild on change
    Serve {
        #[structopt(short = "p", long = "port", default_value = "5000")]
        /// Serve the blog at http://127.0.0.1:<port>
        port: u16,
    },
}

fn main() {
    env_logger::init();

    let opt = Opt::from_args();
    let res = match opt {
        Opt::Init {ref name} => init(name),
        Opt::Build => build(),
        Opt::Serve { port } => serve(port),
    };

    if let Err(ref e) = res {
        print_error(e);
        std::process::exit(1);
    }
}

fn init(name: &str) -> Result<()> {
    let dir = env::current_dir()?.join(name);
    let mut mb = Mdblog::new(dir)?;
    mb.init()?;
    Ok(())
}

fn build() -> Result<()> {
    let root_dir = env::current_dir()?;
    let mut mb = Mdblog::new(&root_dir)?;
    mb.load()?;
    mb.build()?;
    Ok(())
}

fn serve(port: u16) -> Result<()> {
    let root_dir = env::current_dir()?;
    let mut mb = Mdblog::new(&root_dir)?;
    mb.load()?;
    mb.build()?;
    mb.serve(port)?;
    Ok(())
}
<commit_msg>consistent name<commit_after>extern crate log;
extern crate env_logger;
#[macro_use]
extern crate structopt;
extern crate failure;
extern crate mdblog;

use std::env;
use structopt::StructOpt;
use mdblog::{Mdblog, Result, print_error};

#[derive(StructOpt, Debug)]
#[structopt(name = "mdblog")]
/// static site generator from markdown files
enum Opt {
    #[structopt(name = "init")]
    /// Initialize the blog directory layout
    Init {
        /// the blog directory name
        name: String,
    },
    #[structopt(name = "build")]
    /// Build the blog static files
    Build,
    #[structopt(name = "serve")]
    /// Serve the blog, rebuild on change
    Serve {
        #[structopt(short = "p", long = "port", default_value = "5000")]
        /// Serve the blog at http://127.0.0.1:<port>
        port: u16,
    },
}

fn main() {
    env_logger::init();

    let opt = Opt::from_args();
    let res = match opt {
        Opt::Init {ref name} => init(name),
        Opt::Build => build(),
        Opt::Serve { port } => serve(port),
    };

    if let Err(ref e) = res {
        print_error(e);
        std::process::exit(1);
    }
}

fn init(name: &str) -> Result<()> {
    let root_dir = env::current_dir()?.join(name);
    let mut mb = Mdblog::new(root_dir)?;
    mb.init()?;
    Ok(())
}

fn build() -> Result<()> {
    let root_dir = env::current_dir()?;
    let mut mb = Mdblog::new(&root_dir)?;
    mb.load()?;
    mb.build()?;
    Ok(())
}

fn serve(port: u16) -> Result<()> {
    let root_dir = env::current_dir()?;
    let mut mb = Mdblog::new(&root_dir)?;
    mb.load()?;
    mb.build()?;
    mb.serve(port)?;
    Ok(())
}
<|endoftext|>


<commit_before>#[macro_use]
extern crate clap;
use clap::{Arg, App, SubCommand};
extern crate toml;
extern crate reqwest;
extern crate serde;
extern crate serde_json;
#[macro_use]
extern crate serde_derive;
extern crate glob;

#[macro_use]
extern crate lazy_static;

extern crate libc;

mod structs;
mod ghclient;
mod statics;
use statics::CLIENT;

fn main() {

    let matches = App::new(crate_name!())
        .version(crate_version!())
        .author(crate_authors!())
        .about(crate_description!())
        .arg(Arg::with_name("v")
                 .short("v")
                 .multiple(true)
                 .help("Sets the level of verbosity"))
        .subcommand(SubCommand::with_name("key")
                        .about("get user public key")
                        .arg(Arg::with_name("USER")
                                 .required(true)
                                 .index(1)
                                 .help("user name")))
        .subcommand(SubCommand::with_name("pam").about("execute pam check"))
        .subcommand(SubCommand::with_name("refresh").about("refresh cache"))
        .get_matches();

    if let Some(matches) = matches.subcommand_matches("key") {
        CLIENT.print_user_public_key(matches.value_of("USER").unwrap())
              .unwrap();
    } else if let Some(_) = matches.subcommand_matches("refresh") {
        CLIENT.clear_all_caches().unwrap();
    } else if let Some(_) = matches.subcommand_matches("pam") {
        match std::env::var("PAM_USER") {
            Ok(user) => {
                if CLIENT.check_pam(&user).unwrap() {
                    std::process::exit(0);
                } else {
                    std::process::exit(1)
                }
            }
            Err(e) => println!("PAM_USER: {}", e),
        }
    }

}
<commit_msg>Change the style of determining arguments<commit_after>#[macro_use]
extern crate clap;
use clap::{Arg, App, SubCommand};
extern crate toml;
extern crate reqwest;
extern crate serde;
extern crate serde_json;
#[macro_use]
extern crate serde_derive;
extern crate glob;

#[macro_use]
extern crate lazy_static;

extern crate libc;

mod structs;
mod ghclient;
mod statics;
use statics::CLIENT;

fn main() {

    let matches = App::new(crate_name!())
        .version(crate_version!())
        .author(crate_authors!())
        .about(crate_description!())
        .arg(Arg::with_name("v")
                 .short("v")
                 .multiple(true)
                 .help("Sets the level of verbosity"))
        .subcommand(SubCommand::with_name("key")
                        .about("Gets user public key")
                        .arg(Arg::with_name("USER")
                                 .required(true)
                                 .index(1)
                                 .help("user name")))
        .subcommand(SubCommand::with_name("pam").about("Executes pam check"))
        .subcommand(SubCommand::with_name("cleanup").about("Cleans caches up"))
        .get_matches();

    match matches.subcommand() {
        ("key", Some(sub)) => {
            CLIENT.print_user_public_key(sub.value_of("USER").unwrap())
                  .unwrap()
        }
        ("cleanup", Some(_)) => CLIENT.clear_all_caches().unwrap(),
        ("pam", Some(_)) => {
            match std::env::var("PAM_USER") {
                Ok(user) => {
                    if CLIENT.check_pam(&user).unwrap() {
                        std::process::exit(0);
                    } else {
                        std::process::exit(1)
                    }
                }
                Err(e) => println!("PAM_USER: {}", e),
            }
        }
        (&_, _) => println!("{}", matches.usage()),
    }
}
<|endoftext|>