<commit_before>use std::fs::File;
use std::io::prelude::*;
use std::collections::HashMap;

extern crate clap;
use clap::{Arg, App, SubCommand};
extern crate toml;

extern crate reqwest;
use reqwest::header::Authorization;

extern crate serde;
extern crate serde_json;
#[macro_use]
extern crate serde_derive;

extern crate glob;
use glob::glob;

extern crate libc;
#[derive(Deserialize, Debug)]
struct Config {
    token: String,
    org: String,
    team: String,
    #[serde(default="default_endpoint")]
    endpoint: String,
    #[serde(default="default_home")]
    home: String,
    #[serde(default="default_gid")]
    gid: u64,
    #[serde(default="default_sh")]
    sh: String,
    group: Option<String>,
    #[serde(default="default_cache_duration")]
    cache_duration: u64,
    #[serde(default="default_cert_path")]
    cert_path: String
}

fn default_endpoint() -> String { String::from("https://api.github.com") }
fn default_home() -> String { String::from("/home/{}") }
fn default_gid() -> u64 { 2000 }
fn default_sh() -> String { String::from("/bin/bash") }
fn default_cache_duration() -> u64 { 3600 }
fn default_cert_path() -> String { String::from("/etc/ssl/certs/ca-certificates.crt") }

#[derive(Serialize, Deserialize, Debug)]
struct Team {
    id: u64,
    name: String,
}

#[derive(Serialize, Deserialize, Debug)]
struct Member {
    id: u64,
    login: String,
}

#[derive(Serialize, Deserialize, Debug)]
struct PublicKey {
    id: u64,
    key: String,
}

#[derive(Debug)]
enum CliError {
    Serde(serde_json::Error),
    Reqwest(reqwest::Error),
    Io(std::io::Error),
}

impl From<serde_json::Error> for CliError {fn from(err: serde_json::Error) -> CliError { CliError::Serde(err) }}
impl From<reqwest::Error> for CliError {fn from(err: reqwest::Error) -> CliError { CliError::Reqwest(err) }}
impl From<std::io::Error> for CliError {fn from(err: std::io::Error) -> CliError { CliError::Io(err) }}

fn main() {

    let matches = App::new("ghteam-auth")
                      .version("0.1")
                      .author("Yasuyuki YAMADA <yasuyuki.ymd@gmail.com>")
                      .about("")
                      .arg(Arg::with_name("config")
                               .short("c")
                               .long("config")
                               .value_name("FILE")
                               .help("Sets a custom config file (toml)")
                               .takes_value(true))
                      .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("get user public key")
                                             .arg(Arg::with_name("USER")
                                                      .required(false)
                                                      .index(1)
                                                      .help("user name")))
                      .subcommand(SubCommand::with_name("passwd")
                                             .about("get passwd"))
                      .subcommand(SubCommand::with_name("shadow")
                                             .about("get shadow"))
                      .subcommand(SubCommand::with_name("group")
                                             .about("get group"))
                      .subcommand(SubCommand::with_name("refresh")
                                             .about("refresh cache"))
                      .get_matches();

    let configpath = matches.value_of("config").unwrap_or("/etc/ghteam-auth.conf");
    let client = create_github_client(configpath).unwrap();

    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("passwd") {
        client.get_passwd().unwrap();
    } else if let Some(_) = matches.subcommand_matches("shadow") {
        client.get_shadow().unwrap();
    } else if let Some(_) = matches.subcommand_matches("group") {
        client.get_group().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!("couldn't interpret PAM_USER: {}", e),
        }
    }

}

fn create_github_client( configpath: &str ) -> Result<GithubClient, CliError> {
    let mut file = File::open(configpath)?;
    let mut contents = String::new();
    file.read_to_string(&mut contents).unwrap();
    let config = toml::from_str::<Config>(contents.as_str()).unwrap();
    match std::env::var("SSL_CERT_FILE") {
        Ok(_) => (),
        Err(_) => std::env::set_var("SSL_CERT_FILE", config.cert_path.clone()),
    }
    let client = reqwest::Client::new()?;
    Ok(GithubClient::new(client, config))
}

struct GithubClient {
    client: reqwest::Client,
    conf: Config
}

impl GithubClient {
    fn new(client:reqwest::Client, conf:Config) -> GithubClient {
        GithubClient {client:client, conf:conf}
    }

    fn load_content_from_cache(&self, url:&String) -> Result<(std::fs::Metadata,String),CliError> {
        let mut path = std::env::temp_dir();
        path.push("ghteam-auth-cache");
        path.push(url.as_str());
        let metadata = std::fs::metadata(path.to_str().unwrap())?;
        let mut f = File::open(path.to_str().unwrap())?;
        let mut content = String::new();
        f.read_to_string(&mut content)?;
        Ok((metadata,content))
    }

    fn store_content_to_cache(&self, url:&String, content:&String) -> Result<(),CliError> {
        let mut path = std::env::temp_dir();
        path.push("ghteam-auth-cache");
        path.push(url.as_str());
        let mut dirpath = path.clone(); dirpath.pop();
        std::fs::create_dir_all(dirpath)?;
        let mut f = File::create(path.to_str().unwrap())?;
        f.write(content.as_bytes())?;
        Ok(())
    }

    fn get_content_from_url(&self, url:&String) -> Result<String,CliError> {
        let token = String::from("token ") + self.conf.token.clone().as_str();
        let res = self.client.get(url.as_str()).header(Authorization(token)).send();
        let mut content = String::new();
        res?.read_to_string(&mut content)?;
        self.store_content_to_cache(url,&content)?;
        Ok(content)
    }

    fn get_content(&self, url:&String) -> Result<String,CliError> {
        match self.load_content_from_cache(url) {
            Ok((metadata,cache_content)) => {
                match std::time::SystemTime::now().duration_since(metadata.modified()?) {
                    Ok(caching_duration) => {
                        if caching_duration.as_secs() > self.conf.cache_duration {
                            match self.get_content_from_url(url) {
                                Ok(content_from_url) => Ok(content_from_url),
                                Err(_) => Ok(cache_content)
                            }
                        } else {
                            Ok(cache_content)
                        }
                    },
                    Err(_) => {
                        Ok(cache_content)
                    }
                }
            },
            Err(_) => self.get_content_from_url(url)
        }
    }

    fn print_user_public_key(&self, user:&str) -> Result<(), CliError> {
        let keys = self.get_user_public_key(user)?;
        println!("{}", keys);
        Ok(())
    }

    fn get_user_public_key(&self, user:&str) -> Result<String, CliError> {
        let url = format!("{}/users/{}/keys", self.conf.endpoint, user);
        let content = self.get_content(&url);
        let keys = serde_json::from_str::<Vec<PublicKey>>(content?.as_str())?;
        Ok(keys.iter().map(|k|{k.key.clone()}).collect::<Vec<String>>().join("\n"))
    }

    fn check_pam(&self, user:&String) -> Result<bool, CliError> {
        let teams:HashMap<String,Team> = self.get_teams()?;
        if let Some(team) = teams.get(&self.conf.team.clone()) {
            for member in self.get_members(team.id)? {
                if member.login==*user { return Ok(true) }
            }
        }
        Ok(false)
    }

    fn get_passwd(&self) -> Result<(), CliError> {
        let teams:HashMap<String,Team> = self.get_teams()?;
        if let Some(team) = teams.get(&self.conf.team.clone()) {
            for member in self.get_members(team.id)? {
                println!("{}", self.create_passwd_line(&member));
            }
            Ok(())
        } else {
            Ok(())
        }
    }

    fn get_shadow(&self) -> Result<(), CliError> {
        let teams:HashMap<String,Team> = self.get_teams()?;
        if let Some(team) = teams.get(&self.conf.team.clone()) {
            for member in self.get_members(team.id)? {
                println!("{}", self.create_shadow_line(&member));
            }
            Ok(())
        } else {
            Ok(())
        }
    }

    fn get_group(&self) -> Result<(), CliError> {
        let teams:HashMap<String,Team> = self.get_teams()?;
        if let Some(team) = teams.get(&self.conf.team.clone()) {
            let members = self.get_members(team.id)?;
            println!("{}", self.create_group_line(&team.name, self.conf.gid, &members));
            Ok(())
        } else {
            Ok(())
        }
    }

    fn create_passwd_line(&self, member:&Member) -> String {
        format!("{login}:x:{uid}:{gid}:user@{org}:{home}:{sh}",
                login=member.login,
                uid=member.id,
                gid=self.conf.gid,
                org=self.conf.org,
                home=self.conf.home.replace("{}",member.login.as_str()),
                sh=self.conf.sh,
                )
    }

    fn create_shadow_line(&self, member:&Member) -> String {
        format!("{login}:!!:::::::", login=member.login )
    }

    fn create_group_line(&self, name:&String, id:u64, members:&Vec<Member>) -> String {
        format!("{name}:x:{id}:{members}", name=name, id=id,
                members=members.iter().map(|m|{m.login.clone()}).collect::<Vec<String>>().join(","))
    }

    fn get_teams(&self) -> Result<HashMap<String,Team>, CliError> {
        let url = format!("{}/orgs/{}/teams",self.conf.endpoint, self.conf.org);
        let content = self.get_content(&url)?;
        let teams = serde_json::from_str::<Vec<Team>>(content.as_str())?;
        let mut team_map = HashMap::new();
        for team in teams { team_map.insert(team.name.clone(), team); }
        Ok(team_map)
    }

    fn get_members(&self, mid:u64) -> Result<Vec<Member>, CliError> {
        let url = format!("{}/teams/{}/members",self.conf.endpoint.clone(), mid);
        let content = self.get_content(&url)?;
        let members = serde_json::from_str::<Vec<Member>>(content.as_str())?;
        Ok(members)
    }

    fn clear_all_caches(&self) -> Result<(), CliError> {
        let mut path = std::env::temp_dir();
        path.push("ghteam-auth-cache");
        path.push("**");
        path.push("*");
        for entry in glob(&path.to_str().unwrap()).unwrap() {
            match entry {
                Ok(path) => {if path.is_file() {std::fs::remove_file(path)?}},
                Err(e) => println!("{:?}", e),
            }
        }
        Ok(())
    }

}

#[repr(C)]
#[allow(missing_copy_implementations)]
pub struct Passwd {
    name:   *mut libc::c_char,
    pass:   *mut libc::c_char,
    uid:    libc::uid_t,
    gid:    libc::gid_t,
    gecos:  *mut libc::c_char,
    home:   *mut libc::c_char,
    sh:     *mut libc::c_char,
}
<commit_msg>Rename methods<commit_after>use std::fs::File;
use std::io::prelude::*;
use std::collections::HashMap;

extern crate clap;
use clap::{Arg, App, SubCommand};
extern crate toml;

extern crate reqwest;
use reqwest::header::Authorization;

extern crate serde;
extern crate serde_json;
#[macro_use]
extern crate serde_derive;

extern crate glob;
use glob::glob;

extern crate libc;
#[derive(Deserialize, Debug)]
struct Config {
    token: String,
    org: String,
    team: String,
    #[serde(default="default_endpoint")]
    endpoint: String,
    #[serde(default="default_home")]
    home: String,
    #[serde(default="default_gid")]
    gid: u64,
    #[serde(default="default_sh")]
    sh: String,
    group: Option<String>,
    #[serde(default="default_cache_duration")]
    cache_duration: u64,
    #[serde(default="default_cert_path")]
    cert_path: String
}

fn default_endpoint() -> String { String::from("https://api.github.com") }
fn default_home() -> String { String::from("/home/{}") }
fn default_gid() -> u64 { 2000 }
fn default_sh() -> String { String::from("/bin/bash") }
fn default_cache_duration() -> u64 { 3600 }
fn default_cert_path() -> String { String::from("/etc/ssl/certs/ca-certificates.crt") }

#[derive(Serialize, Deserialize, Debug)]
struct Team {
    id: u64,
    name: String,
}

#[derive(Serialize, Deserialize, Debug)]
struct Member {
    id: u64,
    login: String,
}

#[derive(Serialize, Deserialize, Debug)]
struct PublicKey {
    id: u64,
    key: String,
}

#[derive(Debug)]
enum CliError {
    Serde(serde_json::Error),
    Reqwest(reqwest::Error),
    Io(std::io::Error),
}

impl From<serde_json::Error> for CliError {fn from(err: serde_json::Error) -> CliError { CliError::Serde(err) }}
impl From<reqwest::Error> for CliError {fn from(err: reqwest::Error) -> CliError { CliError::Reqwest(err) }}
impl From<std::io::Error> for CliError {fn from(err: std::io::Error) -> CliError { CliError::Io(err) }}

fn main() {

    let matches = App::new("ghteam-auth")
                      .version("0.1")
                      .author("Yasuyuki YAMADA <yasuyuki.ymd@gmail.com>")
                      .about("")
                      .arg(Arg::with_name("config")
                               .short("c")
                               .long("config")
                               .value_name("FILE")
                               .help("Sets a custom config file (toml)")
                               .takes_value(true))
                      .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("get user public key")
                                             .arg(Arg::with_name("USER")
                                                      .required(false)
                                                      .index(1)
                                                      .help("user name")))
                      .subcommand(SubCommand::with_name("passwd")
                                             .about("get passwd"))
                      .subcommand(SubCommand::with_name("shadow")
                                             .about("get shadow"))
                      .subcommand(SubCommand::with_name("group")
                                             .about("get group"))
                      .subcommand(SubCommand::with_name("refresh")
                                             .about("refresh cache"))
                      .get_matches();

    let configpath = matches.value_of("config").unwrap_or("/etc/ghteam-auth.conf");
    let client = create_github_client(configpath).unwrap();

    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("passwd") {
        client.print_passwd().unwrap();
    } else if let Some(_) = matches.subcommand_matches("shadow") {
        client.print_shadow().unwrap();
    } else if let Some(_) = matches.subcommand_matches("group") {
        client.print_group().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!("couldn't interpret PAM_USER: {}", e),
        }
    }

}

fn create_github_client( configpath: &str ) -> Result<GithubClient, CliError> {
    let mut file = File::open(configpath)?;
    let mut contents = String::new();
    file.read_to_string(&mut contents).unwrap();
    let config = toml::from_str::<Config>(contents.as_str()).unwrap();
    match std::env::var("SSL_CERT_FILE") {
        Ok(_) => (),
        Err(_) => std::env::set_var("SSL_CERT_FILE", config.cert_path.clone()),
    }
    let client = reqwest::Client::new()?;
    Ok(GithubClient::new(client, config))
}

struct GithubClient {
    client: reqwest::Client,
    conf: Config
}

impl GithubClient {
    fn new(client:reqwest::Client, conf:Config) -> GithubClient {
        GithubClient {client:client, conf:conf}
    }

    fn load_content_from_cache(&self, url:&String) -> Result<(std::fs::Metadata,String),CliError> {
        let mut path = std::env::temp_dir();
        path.push("ghteam-auth-cache");
        path.push(url.as_str());
        let metadata = std::fs::metadata(path.to_str().unwrap())?;
        let mut f = File::open(path.to_str().unwrap())?;
        let mut content = String::new();
        f.read_to_string(&mut content)?;
        Ok((metadata,content))
    }

    fn store_content_to_cache(&self, url:&String, content:&String) -> Result<(),CliError> {
        let mut path = std::env::temp_dir();
        path.push("ghteam-auth-cache");
        path.push(url.as_str());
        let mut dirpath = path.clone(); dirpath.pop();
        std::fs::create_dir_all(dirpath)?;
        let mut f = File::create(path.to_str().unwrap())?;
        f.write(content.as_bytes())?;
        Ok(())
    }

    fn get_content_from_url(&self, url:&String) -> Result<String,CliError> {
        let token = String::from("token ") + self.conf.token.clone().as_str();
        let res = self.client.get(url.as_str()).header(Authorization(token)).send();
        let mut content = String::new();
        res?.read_to_string(&mut content)?;
        self.store_content_to_cache(url,&content)?;
        Ok(content)
    }

    fn get_content(&self, url:&String) -> Result<String,CliError> {
        match self.load_content_from_cache(url) {
            Ok((metadata,cache_content)) => {
                match std::time::SystemTime::now().duration_since(metadata.modified()?) {
                    Ok(caching_duration) => {
                        if caching_duration.as_secs() > self.conf.cache_duration {
                            match self.get_content_from_url(url) {
                                Ok(content_from_url) => Ok(content_from_url),
                                Err(_) => Ok(cache_content)
                            }
                        } else {
                            Ok(cache_content)
                        }
                    },
                    Err(_) => {
                        Ok(cache_content)
                    }
                }
            },
            Err(_) => self.get_content_from_url(url)
        }
    }

    fn print_user_public_key(&self, user:&str) -> Result<(), CliError> {
        let keys = self.get_user_public_key(user)?;
        println!("{}", keys);
        Ok(())
    }

    fn get_user_public_key(&self, user:&str) -> Result<String, CliError> {
        let url = format!("{}/users/{}/keys", self.conf.endpoint, user);
        let content = self.get_content(&url);
        let keys = serde_json::from_str::<Vec<PublicKey>>(content?.as_str())?;
        Ok(keys.iter().map(|k|{k.key.clone()}).collect::<Vec<String>>().join("\n"))
    }

    fn check_pam(&self, user:&String) -> Result<bool, CliError> {
        let teams:HashMap<String,Team> = self.get_teams()?;
        if let Some(team) = teams.get(&self.conf.team.clone()) {
            for member in self.get_members(team.id)? {
                if member.login==*user { return Ok(true) }
            }
        }
        Ok(false)
    }

    fn print_passwd(&self) -> Result<(), CliError> {
        let teams:HashMap<String,Team> = self.get_teams()?;
        if let Some(team) = teams.get(&self.conf.team.clone()) {
            for member in self.get_members(team.id)? {
                println!("{}", self.create_passwd_line(&member));
            }
            Ok(())
        } else {
            Ok(())
        }
    }

    fn print_shadow(&self) -> Result<(), CliError> {
        let teams:HashMap<String,Team> = self.get_teams()?;
        if let Some(team) = teams.get(&self.conf.team.clone()) {
            for member in self.get_members(team.id)? {
                println!("{}", self.create_shadow_line(&member));
            }
            Ok(())
        } else {
            Ok(())
        }
    }

    fn print_group(&self) -> Result<(), CliError> {
        let teams:HashMap<String,Team> = self.get_teams()?;
        if let Some(team) = teams.get(&self.conf.team.clone()) {
            let members = self.get_members(team.id)?;
            println!("{}", self.create_group_line(&team.name, self.conf.gid, &members));
            Ok(())
        } else {
            Ok(())
        }
    }

    fn create_passwd_line(&self, member:&Member) -> String {
        format!("{login}:x:{uid}:{gid}:user@{org}:{home}:{sh}",
                login=member.login,
                uid=member.id,
                gid=self.conf.gid,
                org=self.conf.org,
                home=self.conf.home.replace("{}",member.login.as_str()),
                sh=self.conf.sh,
                )
    }

    fn create_shadow_line(&self, member:&Member) -> String {
        format!("{login}:!!:::::::", login=member.login )
    }

    fn create_group_line(&self, name:&String, id:u64, members:&Vec<Member>) -> String {
        format!("{name}:x:{id}:{members}", name=name, id=id,
                members=members.iter().map(|m|{m.login.clone()}).collect::<Vec<String>>().join(","))
    }

    fn get_teams(&self) -> Result<HashMap<String,Team>, CliError> {
        let url = format!("{}/orgs/{}/teams",self.conf.endpoint, self.conf.org);
        let content = self.get_content(&url)?;
        let teams = serde_json::from_str::<Vec<Team>>(content.as_str())?;
        let mut team_map = HashMap::new();
        for team in teams { team_map.insert(team.name.clone(), team); }
        Ok(team_map)
    }

    fn get_members(&self, mid:u64) -> Result<Vec<Member>, CliError> {
        let url = format!("{}/teams/{}/members",self.conf.endpoint.clone(), mid);
        let content = self.get_content(&url)?;
        let members = serde_json::from_str::<Vec<Member>>(content.as_str())?;
        Ok(members)
    }

    fn clear_all_caches(&self) -> Result<(), CliError> {
        let mut path = std::env::temp_dir();
        path.push("ghteam-auth-cache");
        path.push("**");
        path.push("*");
        for entry in glob(&path.to_str().unwrap()).unwrap() {
            match entry {
                Ok(path) => {if path.is_file() {std::fs::remove_file(path)?}},
                Err(e) => println!("{:?}", e),
            }
        }
        Ok(())
    }

}

#[repr(C)]
#[allow(missing_copy_implementations)]
pub struct Passwd {
    name:   *mut libc::c_char,
    pass:   *mut libc::c_char,
    uid:    libc::uid_t,
    gid:    libc::gid_t,
    gecos:  *mut libc::c_char,
    home:   *mut libc::c_char,
    sh:     *mut libc::c_char,
}
<|endoftext|>


<commit_before>// ---------------------------------------------------------------------------------------
// Ruthenium, an ack-like searcher, (c) 2015 Georg Brandl.
// Licensed under the MIT license.
// ---------------------------------------------------------------------------------------

#[macro_use]
extern crate clap;
extern crate libc;
extern crate regex_dfa;
extern crate walkdir;
extern crate memmap;
extern crate scoped_threadpool;
extern crate num_cpus;
extern crate glob;

mod search;
mod ignore;
mod display;
mod options;

use std::cell::RefCell;
use std::cmp::max;
use std::sync::mpsc::{channel, Sender};
use std::thread;
use memmap::{Mmap, Protection};
use scoped_threadpool::Pool;
use walkdir::WalkDirIterator;

use display::DisplayMode;
use search::FileResult;
use options::Opts;

fn walk(chan: Sender<FileResult>, opts: &Opts) {
    let mut pool = Pool::new(max(opts.workers - 1, 1));
    let regex = search::create_rx(&opts);

    let walker = walkdir::WalkDir::new(&opts.path)
        .follow_links(opts.follow_links)
        .max_depth(opts.depth);
    pool.scoped(|scope| {
        let rx = &regex;
        let mut parent_stack: Vec<::std::path::PathBuf> = Vec::new();
        let ignore_stack = RefCell::new(Vec::new()); // XXX: add global ignores from cmdline/config?
        let walker = walker.into_iter().filter_entry(|entry| {
            let mut ignore_stack = ignore_stack.borrow_mut();
            {
                let new_parent = entry.path().parent().unwrap();
                //println!("new_parent: {:?}", new_parent);
                // remove parents that are not applicable anymore
                while !parent_stack.is_empty() &&
                    parent_stack.last().unwrap().as_path() != new_parent
                {
                    //println!("popping");
                    ignore_stack.pop();
                    parent_stack.pop();
                }
            }
            // weed out hidden files
            let path = entry.path();
            if let Some(fname) = path.file_name() {
                if !opts.do_hidden && fname.to_string_lossy().starts_with(".") {
                    return false;
                }
            }
            if opts.check_ignores && ignore::match_patterns(path, &ignore_stack) {
                return false;
            }
            // we got a new dir?
            if entry.file_type().is_dir() {
                let new_path = entry.path().to_path_buf();
                // read ignore patterns specific to this directory
                ignore_stack.push(ignore::read_patterns(&new_path));
                parent_stack.push(new_path);
            }
            //println!("{:?} {:?}", entry.path(), parent_stack);
            true
        });
        for entry in walker {
            if let Ok(entry) = entry {
                // weed out further special files
                if !entry.file_type().is_file() {
                    continue;
                }
                // open and search file in one of the worker threads
                let ch = chan.clone();
                scope.execute(move || {
                    let path = entry.path();
                    if let Ok(map) = Mmap::open_path(path, Protection::Read) {
                        let buf = unsafe { map.as_slice() };
                        let res = search::search(rx, &opts, path, buf);
                        ch.send(res).unwrap();
                    }
                });
            }
        }
    });
}

fn run<D: DisplayMode>(display: &mut D, opts: Opts) {
    let (w_chan, r_chan) = channel();
    thread::spawn(move || {
        walk(w_chan, &opts);
    });
    while let Ok(r) = r_chan.recv() {
        display.print_result(r);
    }
}

fn main() {
    let mut opts = Opts::from_cmdline();
    let colors = opts.colors.take().unwrap();
    if opts.only_count {
        run(&mut display::CountMode::new(colors), opts);
    } else if opts.only_files == Some(true) {
        run(&mut display::FilesOnlyMode::new(colors, true), opts);
    } else if opts.only_files == Some(false) {
        run(&mut display::FilesOnlyMode::new(colors, false), opts);
    } else if opts.ackmate_format {
        run(&mut display::AckMateMode::new(), opts);
    } else if opts.vimgrep_format {
        run(&mut display::VimGrepMode, opts);
    } else if !opts.show_heading {
        run(&mut display::OneLineMode::new(colors, opts.show_break), opts);
    } else {
        run(&mut display::DefaultMode::new(colors, opts.show_break), opts);
    }
}
<commit_msg>Remove unnecessary RefCell.<commit_after>// ---------------------------------------------------------------------------------------
// Ruthenium, an ack-like searcher, (c) 2015 Georg Brandl.
// Licensed under the MIT license.
// ---------------------------------------------------------------------------------------

#[macro_use]
extern crate clap;
extern crate libc;
extern crate regex_dfa;
extern crate walkdir;
extern crate memmap;
extern crate scoped_threadpool;
extern crate num_cpus;
extern crate glob;

mod search;
mod ignore;
mod display;
mod options;

use std::cmp::max;
use std::sync::mpsc::{channel, Sender};
use std::thread;
use memmap::{Mmap, Protection};
use scoped_threadpool::Pool;
use walkdir::WalkDirIterator;

use display::DisplayMode;
use search::FileResult;
use options::Opts;

fn walk(chan: Sender<FileResult>, opts: &Opts) {
    let mut pool = Pool::new(max(opts.workers - 1, 1));
    let regex = search::create_rx(&opts);

    let walker = walkdir::WalkDir::new(&opts.path)
        .follow_links(opts.follow_links)
        .max_depth(opts.depth);
    pool.scoped(|scope| {
        let rx = &regex;
        let mut parent_stack: Vec<::std::path::PathBuf> = Vec::new();
        // stack of Ignore structs per directory, they accumulate
        // XXX: add global ignores from cmdline and a config file here
        let mut ignore_stack = Vec::new();
        let walker = walker.into_iter().filter_entry(|entry| {
            {
                let new_parent = entry.path().parent().unwrap();
                //println!("new_parent: {:?}", new_parent);
                // remove parents that are not applicable anymore
                while !parent_stack.is_empty() &&
                    parent_stack.last().unwrap().as_path() != new_parent
                {
                    //println!("popping");
                    ignore_stack.pop();
                    parent_stack.pop();
                }
            }
            // weed out hidden files
            let path = entry.path();
            if let Some(fname) = path.file_name() {
                if !opts.do_hidden && fname.to_string_lossy().starts_with(".") {
                    return false;
                }
            }
            if opts.check_ignores && ignore::match_patterns(path, &ignore_stack) {
                return false;
            }
            // we got a new dir?
            if entry.file_type().is_dir() {
                let new_path = entry.path().to_path_buf();
                // read ignore patterns specific to this directory
                ignore_stack.push(ignore::read_patterns(&new_path));
                parent_stack.push(new_path);
            }
            //println!("{:?} {:?}", entry.path(), parent_stack);
            true
        });
        for entry in walker {
            if let Ok(entry) = entry {
                // weed out further special files
                if !entry.file_type().is_file() {
                    continue;
                }
                // open and search file in one of the worker threads
                let ch = chan.clone();
                scope.execute(move || {
                    let path = entry.path();
                    if let Ok(map) = Mmap::open_path(path, Protection::Read) {
                        let buf = unsafe { map.as_slice() };
                        let res = search::search(rx, &opts, path, buf);
                        ch.send(res).unwrap();
                    }
                });
            }
        }
    });
}

fn run<D: DisplayMode>(display: &mut D, opts: Opts) {
    let (w_chan, r_chan) = channel();
    thread::spawn(move || {
        walk(w_chan, &opts);
    });
    while let Ok(r) = r_chan.recv() {
        display.print_result(r);
    }
}

fn main() {
    let mut opts = Opts::from_cmdline();
    let colors = opts.colors.take().unwrap();
    if opts.only_count {
        run(&mut display::CountMode::new(colors), opts);
    } else if opts.only_files == Some(true) {
        run(&mut display::FilesOnlyMode::new(colors, true), opts);
    } else if opts.only_files == Some(false) {
        run(&mut display::FilesOnlyMode::new(colors, false), opts);
    } else if opts.ackmate_format {
        run(&mut display::AckMateMode::new(), opts);
    } else if opts.vimgrep_format {
        run(&mut display::VimGrepMode, opts);
    } else if !opts.show_heading {
        run(&mut display::OneLineMode::new(colors, opts.show_break), opts);
    } else {
        run(&mut display::DefaultMode::new(colors, opts.show_break), opts);
    }
}
<|endoftext|>


<commit_before>use std::path::PathBuf;
use std::result::Result as RResult;

pub use entry::Entry;
pub use error::StoreError;

pub type Result<T> = RResult<T, StoreError>;

pub struct Store {
    location: PathBuf,
}

impl Store {

    pub fn create(entry: Entry) -> Result<()> {
        unimplemented!()
    }

    pub fn read(path: PathBuf) -> Result<Entry> {
        unimplemented!()
    }

    pub fn update(entry: Entry) -> Result<()> {
        unimplemented!()
    }

    pub fn delete(path: PathBuf) -> Result<()> {
        unimplemented!()
    }

}

<commit_msg>Fixup: Store type: read() should return Arc<RWLock<>>, update() should take that<commit_after>use std::path::PathBuf;
use std::result::Result as RResult;
use std::sync::Arc;
use std::sync::RWLock;

pub use entry::Entry;
pub use error::StoreError;

pub type Result<T> = RResult<T, StoreError>;

pub struct Store {
    location: PathBuf,
}

impl Store {

    pub fn create(entry: Entry) -> Result<()> {
        unimplemented!()
    }

    pub fn read(path: PathBuf) -> Result<Arc<RWLock<Entry>>> {
        unimplemented!()
    }

    pub fn update(entry: Arc<RWLock<Entry>>) -> Result<()> {
        unimplemented!()
    }

    pub fn delete(path: PathBuf) -> Result<()> {
        unimplemented!()
    }

}

<|endoftext|>


<commit_before>#[macro_use] extern crate clap;
#[macro_use] extern crate log;
extern crate env_logger;

mod cli;
mod cd;

use std::process::exit;

fn main() {
    env_logger::init().expect("Failed to initialize logger.");

    match run_cli() {
        Ok(_) => {},
        Err((message, exit_code)) => {
            error!("Error: {}", message);
            exit(exit_code);
        },
    }
}

fn run_cli() -> Result<(), (String, i32)> {
    let matches = cli::app().get_matches();

    let verbose_level = match matches.occurrences_of("verbose") {
        0...4 => matches.occurrences_of("verbose"),
        _ => 4,
    };

    match matches.subcommand_name() {
        Some("cd") => try!(cd::open_shell_at_repo(matches.subcommand_matches("cd").unwrap())),
        None       => panic!("Subcommand is required, so no idea how we got here!"),
        _          => println!("'{}' is not implemented yet.", matches.subcommand_name().unwrap()),
    };

    Ok(())
}
<commit_msg>Remove redundant "Error" from error messages<commit_after>#[macro_use] extern crate clap;
#[macro_use] extern crate log;
extern crate env_logger;

mod cli;
mod cd;

use std::process::exit;

fn main() {
    env_logger::init().expect("Failed to initialize logger.");

    match run_cli() {
        Ok(_) => {},
        Err((message, exit_code)) => {
            error!("{}", message);
            exit(exit_code);
        },
    }
}

fn run_cli() -> Result<(), (String, i32)> {
    let matches = cli::app().get_matches();

    let verbose_level = match matches.occurrences_of("verbose") {
        0...4 => matches.occurrences_of("verbose"),
        _ => 4,
    };

    match matches.subcommand_name() {
        Some("cd") => try!(cd::open_shell_at_repo(matches.subcommand_matches("cd").unwrap())),
        None       => panic!("Subcommand is required, so no idea how we got here!"),
        _          => println!("'{}' is not implemented yet.", matches.subcommand_name().unwrap()),
    };

    Ok(())
}
<|endoftext|>


<commit_before>#[macro_use]
extern crate imgui;
extern crate mush;
use mush::interface::Interface;
use imgui::Ui;

const CLEAR_COLOR: (f32, f32, f32, f32) = (0.006, 0.006, 0.006, 1.0);

fn main() {
    let mut ifc = Interface::init();
    let mut state = State::default();

    loop {
        let r = ifc.render(CLEAR_COLOR, |ui| { menu(ui, &mut state) } );
        if !r | state.exit{ break }
    }
}

struct State {
    exit: bool,
}
impl Default for State {
    fn default() -> Self {
        State { exit: false }
    }
}

fn menu (ui: &Ui, state: &mut State) {
    ui.main_menu_bar(|| {
        ui.menu(im_str!("File"))
            .build(|| {
                ui.menu_item(im_str!("Exit"))
                    .selected(&mut state.exit)
                    .build();
            });
    });
}
<commit_msg>wip: open files<commit_after>#[macro_use]
extern crate imgui;
extern crate mush;
use mush::interface::Interface;
use imgui::Ui;

const CLEAR_COLOR: (f32, f32, f32, f32) = (0.006, 0.006, 0.006, 1.0);

fn main() {
    let mut ifc = Interface::init();
    let mut state = State::default();

    loop {
        let r = ifc.render(CLEAR_COLOR, |ui| { menu(ui, &mut state) } );
        if !r | state.exit{ break }
    }
}

struct State {
    exit: bool,
}
impl Default for State {
    fn default() -> Self {
        State {
            exit: false,
        }
    }
}

fn menu (ui: &Ui, state: &mut State) {
    let mut opening = false;

    ui.main_menu_bar(|| {
        ui.menu(im_str!("File"))
            .build(|| {
                ui.menu_item(im_str!("Open"))
                    .selected(&mut opening)
                    .build();

                ui.menu_item(im_str!("Exit"))
                    .selected(&mut state.exit)
                    .build();
            });
    });

    if opening { ui.open_popup(im_str!("select-file")); }
    ui.popup(im_str!("select-file"), || {
        ui.text(im_str!("Select File"));
        ui.separator();

    });
}
<|endoftext|>


<commit_before>extern crate clap;
extern crate env_logger;
extern crate guzuta;

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

    let app = clap::App::new("guzuta")
        .version("0.0.0")
        .about("Custom repository manager for ArchLinux pacman")
        .subcommand(clap::SubCommand::with_name("repo-add")
            .about("Add PACKAGE_PATH to DB_PATH")
            .arg(clap::Arg::with_name("repo-key")
                .long("repo-key")
                .help("GPG key to sign repository database"))
            .arg(clap::Arg::with_name("PACKAGE_PATH")
                .required(true)
                .help("Path to package to be added"))
            .arg(clap::Arg::with_name("DB_PATH")
                .required(true)
                .help("Path to repository database")))
        .subcommand(clap::SubCommand::with_name("repo-remove")
            .about("Remove PACKAGE_NAME to DB_PATH")
            .arg(clap::Arg::with_name("repo-key")
                .long("repo-key")
                .help("GPG key to sign repository database"))
            .arg(clap::Arg::with_name("PACKAGE_NAME")
                .required(true)
                .help("Path to package to be removed"))
            .arg(clap::Arg::with_name("DB_PATH")
                .required(true)
                .help("Path to repository database")))
        .subcommand(clap::SubCommand::with_name("files-add")
            .about("Add PACKAGE_PATH to FILES_PATH")
            .arg(clap::Arg::with_name("repo-key")
                .long("repo-key")
                .help("GPG key to sign repository database"))
            .arg(clap::Arg::with_name("PACKAGE_PATH")
                .required(true)
                .help("Path to package to be added"))
            .arg(clap::Arg::with_name("FILES_PATH")
                .required(true)
                .help("Path to repository database")));
    let matches = app.clone().get_matches();

    run_subcommand(matches.subcommand());
}

fn run_subcommand(subcommand: (&str, Option<&clap::ArgMatches>)) {
    match subcommand {
        ("repo-add", Some(repo_add_command)) => {
            repo_add(repo_add_command);
        }
        ("repo-remove", Some(repo_remove_command)) => {
            repo_remove(repo_remove_command);
        }
        ("files-add", Some(files_add_command)) => {
            files_add(files_add_command);
        }
        _ => {
            panic!("Unknown subcommand");
        }
    }
}

fn repo_add(args: &clap::ArgMatches) {
    let signer = args.value_of("repo-key").map(|key| guzuta::Signer::new(key.to_owned()));
    let package = guzuta::Package::load(&args.value_of("PACKAGE_PATH").unwrap());
    let mut repository = guzuta::Repository::new(args.value_of("DB_PATH").unwrap().to_owned(),
                                                 signer);

    repository.load();
    repository.add(&package);
    repository.save(false);
}

fn repo_remove(args: &clap::ArgMatches) {
    let signer = args.value_of("repo-key").map(|key| guzuta::Signer::new(key.to_owned()));
    let package_name = args.value_of("PACKAGE_NAME").unwrap();
    let mut repository = guzuta::Repository::new(args.value_of("DB_PATH").unwrap().to_owned(),
                                                 signer);

    repository.load();
    repository.remove(&package_name);
    repository.save(false);
}

fn files_add(args: &clap::ArgMatches) {
    let signer = args.value_of("repo-key").map(|key| guzuta::Signer::new(key.to_owned()));
    let package = guzuta::Package::load(&args.value_of("PACKAGE_PATH").unwrap());
    let mut repository = guzuta::Repository::new(args.value_of("FILES_PATH").unwrap().to_owned(),
                                                 signer);

    repository.load();
    repository.add(&package);
    repository.save(true);
}
<commit_msg>Add files-remove subcommand<commit_after>extern crate clap;
extern crate env_logger;
extern crate guzuta;

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

    let app = clap::App::new("guzuta")
        .version("0.0.0")
        .about("Custom repository manager for ArchLinux pacman")
        .subcommand(clap::SubCommand::with_name("repo-add")
            .about("Add PACKAGE_PATH to DB_PATH")
            .arg(clap::Arg::with_name("repo-key")
                .long("repo-key")
                .help("GPG key to sign repository database"))
            .arg(clap::Arg::with_name("PACKAGE_PATH")
                .required(true)
                .help("Path to package to be added"))
            .arg(clap::Arg::with_name("DB_PATH")
                .required(true)
                .help("Path to repository database")))
        .subcommand(clap::SubCommand::with_name("repo-remove")
            .about("Remove PACKAGE_NAME from DB_PATH")
            .arg(clap::Arg::with_name("repo-key")
                .long("repo-key")
                .help("GPG key to sign repository database"))
            .arg(clap::Arg::with_name("PACKAGE_NAME")
                .required(true)
                .help("Path to package to be removed"))
            .arg(clap::Arg::with_name("DB_PATH")
                .required(true)
                .help("Path to repository database")))
        .subcommand(clap::SubCommand::with_name("files-add")
            .about("Add PACKAGE_PATH to FILES_PATH")
            .arg(clap::Arg::with_name("repo-key")
                .long("repo-key")
                .help("GPG key to sign repository database"))
            .arg(clap::Arg::with_name("PACKAGE_PATH")
                .required(true)
                .help("Path to package to be added"))
            .arg(clap::Arg::with_name("FILES_PATH")
                .required(true)
                .help("Path to repository database")))
        .subcommand(clap::SubCommand::with_name("files-remove")
            .about("Remove PACKAGE_NAME from FILES_PATH")
            .arg(clap::Arg::with_name("repo-key")
                .long("repo-key")
                .help("GPG key to sign repository database"))
            .arg(clap::Arg::with_name("PACKAGE_NAME")
                .required(true)
                .help("Path to package to be removed"))
            .arg(clap::Arg::with_name("DB_PATH")
                .required(true)
                .help("Path to repository database")));
    let matches = app.clone().get_matches();

    run_subcommand(matches.subcommand());
}

fn run_subcommand(subcommand: (&str, Option<&clap::ArgMatches>)) {
    match subcommand {
        ("repo-add", Some(repo_add_command)) => {
            repo_add(repo_add_command);
        }
        ("repo-remove", Some(repo_remove_command)) => {
            repo_remove(repo_remove_command);
        }
        ("files-add", Some(files_add_command)) => {
            files_add(files_add_command);
        }
        ("files-remove", Some(files_remove_command)) => {
            files_remove(files_remove_command);
        }
        _ => {
            panic!("Unknown subcommand");
        }
    }
}

fn repo_add(args: &clap::ArgMatches) {
    let signer = args.value_of("repo-key").map(|key| guzuta::Signer::new(key.to_owned()));
    let package = guzuta::Package::load(&args.value_of("PACKAGE_PATH").unwrap());
    let mut repository = guzuta::Repository::new(args.value_of("DB_PATH").unwrap().to_owned(),
                                                 signer);

    repository.load();
    repository.add(&package);
    repository.save(false);
}

fn repo_remove(args: &clap::ArgMatches) {
    let signer = args.value_of("repo-key").map(|key| guzuta::Signer::new(key.to_owned()));
    let package_name = args.value_of("PACKAGE_NAME").unwrap();
    let mut repository = guzuta::Repository::new(args.value_of("DB_PATH").unwrap().to_owned(),
                                                 signer);

    repository.load();
    repository.remove(&package_name);
    repository.save(false);
}

fn files_add(args: &clap::ArgMatches) {
    let signer = args.value_of("repo-key").map(|key| guzuta::Signer::new(key.to_owned()));
    let package = guzuta::Package::load(&args.value_of("PACKAGE_PATH").unwrap());
    let mut repository = guzuta::Repository::new(args.value_of("FILES_PATH").unwrap().to_owned(),
                                                 signer);

    repository.load();
    repository.add(&package);
    repository.save(true);
}

fn files_remove(args: &clap::ArgMatches) {
    let signer = args.value_of("repo-key").map(|key| guzuta::Signer::new(key.to_owned()));
    let package_name = args.value_of("PACKAGE_NAME").unwrap();
    let mut repository = guzuta::Repository::new(args.value_of("DB_PATH").unwrap().to_owned(),
                                                 signer);

    repository.load();
    repository.remove(&package_name);
    repository.save(true);
}
<|endoftext|>


<commit_before>extern crate turtle;

use std::fmt;
use std::fs::File;
use turtle::{Canvas, Turtle};

#[derive(Debug, Eq, PartialEq, Clone)]
struct Character(char);

#[derive(Eq, PartialEq, Clone)]
struct Symbol {
    character: Character,
}

impl fmt::Debug for Symbol {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}", self.character.0)
    }
}

#[derive(Clone)]
struct SymbolString(Vec<Symbol>);

impl fmt::Debug for SymbolString {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let v = &self.0;
        try!(write!(f, "\""));
        if !v.is_empty() {
            try!(write!(f, "{:?}", v[0]));
            for e in &v[1..] {
                try!(write!(f, " {:?}", e));
            }
        }
        write!(f, "\"")
    }
}

impl SymbolString {
    fn from_str(s: &str) -> SymbolString {
        SymbolString(s.chars().filter(|&c| !c.is_whitespace()).map(|c| Symbol{character: Character(c)}).collect())
    }
}

#[derive(Debug)]
struct Rule {
    lhs: Symbol,
    rhs: SymbolString,
}

impl Rule {
    fn produce(&self, sym: &Symbol) -> Option<SymbolString> {
        if self.lhs.eq(sym) {
            Some(self.rhs.clone())
        } else {
            None
        }
    }
}

#[derive(Debug)]
struct System {
    rules: Vec<Rule>,
}

impl System {
    fn develop(&self, axiom: SymbolString, iterations: usize) -> (SymbolString, usize) {
        let mut current = axiom;

        for iter in 0..iterations {
            let (next, progress) = self.develop1(&current);
            if !progress {
                return (current, iter);
            }
            current = next;
        }
        return (current, iterations);
    }

    fn develop1(&self, axiom: &SymbolString) -> (SymbolString, bool) {
        let mut expanded = Vec::new();
        let mut any_rule_applied = false;

        for symbol in axiom.0.iter() {
            let mut found = false;
            for rule in self.rules.iter() {
                if let Some(rhs) = rule.produce(&symbol) {
                    expanded.extend(rhs.0);
                    any_rule_applied = true;
                    found = true;
                    break;
                }
            }
            if !found {
                expanded.push(symbol.clone());
            }
        }

        (SymbolString(expanded), any_rule_applied)
    }
}
fn sym(c: char) -> Symbol {
    Symbol { character: Character(c) }
}

fn draw(symstr: &SymbolString, angle: f32, distance: f32, filename: &str) {
    let mut t = Canvas::new();
    t.pendown();
    for sym in symstr.0.iter() {
        match sym.character.0 {
            'F' => t.forward(distance),
            '+' => t.right(angle),
            '-' => t.left(angle),
            _   => {}
        }
    }
    t.save_svg(&mut File::create(filename).unwrap()).unwrap();
}

fn koch_curve(maxiter: usize) {
    let axiom = SymbolString::from_str("F++F++F");

    let system = System { rules: vec![
        Rule {
            lhs: sym('F'),
            rhs: SymbolString::from_str("F-F++F-F")
        }
        ] };
    println!("{:?}", system);

    println!("before: {:?}", axiom);
    let (after, iters) = system.develop(axiom, maxiter);
    println!("after:  {:?}", after);

    draw(&after, 60.0, 10.0, &format!("koch_{:02}.svg", iters));
}

fn dragon_curve(maxiter: usize) {
    let axiom = SymbolString::from_str("FX");

    let system = System { rules: vec![
        Rule {
            lhs: sym('X'),
            rhs: SymbolString::from_str("X+YF+")
        },
        Rule {
            lhs: sym('Y'),
            rhs: SymbolString::from_str("-FX-Y")
        }
        ] };
    println!("{:?}", system);

    println!("before: {:?}", axiom);
    let (after, iters) = system.develop(axiom, maxiter);
    println!("after:  {:?}", after);

    draw(&after, 90.0, 10.0, &format!("dragon_{:02}.svg", iters));
}

fn main() {
    for i in 0..7 {
        koch_curve(i);
    }
    for i in 0..16 {
        dragon_curve(i);
    }
}
<commit_msg>Add other examples<commit_after>extern crate turtle;

use std::fmt;
use std::fs::File;
use turtle::{Canvas, Turtle};

#[derive(Debug, Eq, PartialEq, Clone)]
struct Character(char);

#[derive(Eq, PartialEq, Clone)]
struct Symbol {
    character: Character,
}

impl fmt::Debug for Symbol {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}", self.character.0)
    }
}

#[derive(Clone)]
struct SymbolString(Vec<Symbol>);

impl fmt::Debug for SymbolString {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let v = &self.0;
        try!(write!(f, "\""));
        if !v.is_empty() {
            try!(write!(f, "{:?}", v[0]));
            for e in &v[1..] {
                try!(write!(f, " {:?}", e));
            }
        }
        write!(f, "\"")
    }
}

impl SymbolString {
    fn from_str(s: &str) -> SymbolString {
        SymbolString(s.chars().filter(|&c| !c.is_whitespace()).map(|c| Symbol{character: Character(c)}).collect())
    }
}

#[derive(Debug)]
struct Rule {
    lhs: Symbol,
    rhs: SymbolString,
}

impl Rule {
    fn produce(&self, sym: &Symbol) -> Option<SymbolString> {
        if self.lhs.eq(sym) {
            Some(self.rhs.clone())
        } else {
            None
        }
    }
}

#[derive(Debug)]
struct System {
    rules: Vec<Rule>,
}

impl System {
    fn develop(&self, axiom: SymbolString, iterations: usize) -> (SymbolString, usize) {
        let mut current = axiom;

        for iter in 0..iterations {
            let (next, progress) = self.develop1(&current);
            if !progress {
                return (current, iter);
            }
            current = next;
        }
        return (current, iterations);
    }

    fn develop1(&self, axiom: &SymbolString) -> (SymbolString, bool) {
        let mut expanded = Vec::new();
        let mut any_rule_applied = false;

        for symbol in axiom.0.iter() {
            let mut found = false;
            for rule in self.rules.iter() {
                if let Some(rhs) = rule.produce(&symbol) {
                    expanded.extend(rhs.0);
                    any_rule_applied = true;
                    found = true;
                    break;
                }
            }
            if !found {
                expanded.push(symbol.clone());
            }
        }

        (SymbolString(expanded), any_rule_applied)
    }
}
fn sym(c: char) -> Symbol {
    Symbol { character: Character(c) }
}

fn draw(symstr: &SymbolString, init_direction: f32, angle: f32, distance: f32, filename: &str) {
    let mut t = Canvas::new();
    t.pendown();
    t.right(init_direction);
    for sym in symstr.0.iter() {
        match sym.character.0 {
            'F' => t.forward(distance),
            '+' => t.right(angle),
            '-' => t.left(angle),
            '[' => t.push(),
            ']' => t.pop(),
            _   => {}
        }
    }
    t.save_svg(&mut File::create(filename).unwrap()).unwrap();
}

fn koch_curve(maxiter: usize) {
    let axiom = SymbolString::from_str("F++F++F");

    let system = System { rules: vec![
        Rule {
            lhs: sym('F'),
            rhs: SymbolString::from_str("F-F++F-F")
        }
        ] };
    println!("{:?}", system);

    let (after, iters) = system.develop(axiom, maxiter);

    draw(&after, 0.0, 60.0, 10.0, &format!("koch_{:02}.svg", iters));
}

fn dragon_curve(maxiter: usize) {
    let axiom = SymbolString::from_str("FX");

    let system = System { rules: vec![
        Rule {
            lhs: sym('X'),
            rhs: SymbolString::from_str("X+YF+")
        },
        Rule {
            lhs: sym('Y'),
            rhs: SymbolString::from_str("-FX-Y")
        }
        ] };
    println!("{:?}", system);

    let (after, iters) = system.develop(axiom, maxiter);

    draw(&after, -90.0, 90.0, 10.0, &format!("dragon_{:02}.svg", iters));
}

fn sierpinski_triangle(maxiter: usize) {
    let axiom = SymbolString::from_str("A");

    let system = System { rules: vec![
        Rule {
            lhs: sym('A'),
            rhs: SymbolString::from_str("+B-A-B+")
        },
        Rule {
            lhs: sym('B'),
            rhs: SymbolString::from_str("-A+B+A-")
        }
        ] };
    println!("{:?}", system);

    let (after, iters) = system.develop(axiom, maxiter);

    // replace A and B with F
    let system = System { rules: vec![
        Rule {
            lhs: sym('A'),
            rhs: SymbolString::from_str("F")
        },
        Rule {
            lhs: sym('B'),
            rhs: SymbolString::from_str("F")
        }
        ] };
    let (after, _iters) = system.develop1(&after);

    draw(&after, 0.0, 60.0, 10.0, &format!("sierpinski_{:02}.svg", iters));
}

fn fractal_plant(maxiter: usize) {
    let axiom = SymbolString::from_str("X");

    let system = System { rules: vec![
        Rule {
            lhs: sym('X'),
            rhs: SymbolString::from_str("F-[[X]+X]+F[+FX]-X")
        },
        Rule {
            lhs: sym('F'),
            rhs: SymbolString::from_str("FF")
        }
        ] };
    println!("{:?}", system);

    let (after, iters) = system.develop(axiom, maxiter);

    draw(&after, -90.0, 25.0, 10.0, &format!("plant_{:02}.svg", iters));
}

fn main() {
    for i in 0..7 {
        koch_curve(i);
    }
    for i in 0..16 {
        dragon_curve(i);
    }
    for i in 0..10 {
        sierpinski_triangle(i);
    }
    for i in 4..8 {
        fractal_plant(i);
    }
}
<|endoftext|>


<commit_before>// Playing with paths.

extern crate chrono;
extern crate rsure;
extern crate env_logger;
extern crate regex;

#[macro_use]
extern crate log;

#[macro_use]
extern crate clap;

use chrono::Local;
use clap::{App, AppSettings, Arg, SubCommand};

use std::collections::BTreeMap;
use std::path::Path;

use rsure::{show_tree, Progress, SureHash, TreeCompare, stdout_visitor, parse_store, StoreTags,
            StoreVersion, Version};

mod bkcmd;

// For now, just use the crate's error type.
pub use rsure::Result;

#[allow(dead_code)]
fn main() {
    env_logger::init().unwrap();

    let matches = App::new("rsure")
        .version(crate_version!())
        .setting(AppSettings::GlobalVersion)
        .arg(
            Arg::with_name("file")
                .short("f")
                .long("file")
                .takes_value(true)
                .help(
                    "Base of file name, default 2sure, will get .dat.gz appended",
                ),
        )
        .arg(
            Arg::with_name("dir")
                .short("d")
                .long("dir")
                .takes_value(true)
                .help("Directory to scan, defaults to \".\""),
        )
        .arg(
            Arg::with_name("tag")
                .long("tag")
                .takes_value(true)
                .multiple(true)
                .help("key=value to associate with scan"),
        )
        .arg(
            Arg::with_name("version")
                .short("v")
                .long("version")
                .takes_value(true)
                .help("Version of sure data to use (see 'list' output)"),
        )
        .setting(AppSettings::SubcommandRequired)
        .subcommand(SubCommand::with_name("scan").about(
            "Scan a directory for the first time",
        ))
        .subcommand(SubCommand::with_name("update").about(
            "Update the scan using the dat file",
        ))
        .subcommand(SubCommand::with_name("check").about(
            "Compare the directory with the dat file",
        ))
        .subcommand(SubCommand::with_name("signoff").about(
            "Compare the dat file with the bak file",
        ))
        .subcommand(SubCommand::with_name("show").about(
            "Pretty print the dat file",
        ))
        .subcommand(
            SubCommand::with_name("bknew")
                .about("Create a new bitkeeper-based sure store")
                .arg(Arg::with_name("dir").required(true).help(
                    "Directory to create bk-based store",
                )),
        )
        .subcommand(
            SubCommand::with_name("bkimport")
                .about("Import a tree of surefiles into a bk store")
                .arg(
                    Arg::with_name("src")
                        .long("src")
                        .takes_value(true)
                        .required(true),
                )
                .arg(
                    Arg::with_name("dest")
                        .long("dest")
                        .takes_value(true)
                        .required(true),
                ),
        )
        .subcommand(SubCommand::with_name("list").about(
            "List revisions in a given sure store",
        ))
        .get_matches();

    let dir = matches.value_of("dir").unwrap_or(".");

    let file = matches.value_of("file").unwrap_or("2sure.dat.gz");
    let store = parse_store(file).unwrap();

    let mut tags = decode_tags(matches.values_of("tag"));

    add_name_tag(&mut tags, &dir);

    // Note that only the "check" command uses the version tag.
    let latest = match matches.value_of("version") {
        None => Version::Latest,
        Some(x) => Version::Tagged(x.to_string()),
    };

    match matches.subcommand() {
        ("scan", Some(_)) => {
            rsure::update(&dir, &*store, false, &tags).unwrap();
        }
        ("update", Some(_)) => {
            rsure::update(&dir, &*store, true, &tags).unwrap();
        }
        ("check", Some(_)) => {
            let old_tree = store.load(latest).unwrap();
            let mut new_tree = rsure::scan_fs(&dir).unwrap();
            let estimate = new_tree.hash_estimate();
            let pdir = &Path::new(dir);
            let mut progress = Progress::new(estimate.files, estimate.bytes);
            new_tree.hash_update(pdir, &mut progress);
            progress.flush();
            info!("check {:?}", file);
            new_tree.compare_from(&mut stdout_visitor(), &old_tree, pdir);
        }
        ("signoff", Some(_)) => {
            let old_tree = store.load(Version::Prior).unwrap();
            let new_tree = store.load(Version::Latest).unwrap();
            println!("signoff {}", file);
            new_tree.compare_from(&mut stdout_visitor(), &old_tree, &Path::new(dir));
        }
        ("show", Some(_)) => {
            println!("show {}", file);
            show_tree(&Path::new(&file)).unwrap();
        }
        ("bknew", Some(sub)) => {
            let bkdir = sub.value_of("dir").unwrap();
            bkcmd::new(bkdir).unwrap();
        }
        ("bkimport", Some(sub)) => {
            let src = sub.value_of("src").unwrap();
            let dest = sub.value_of("dest").unwrap();
            bkcmd::import(src, dest).unwrap();
        }
        ("list", Some(_)) => {
            let version = store.get_versions().unwrap();
            dump_versions(&version);
        }
        _ => {
            panic!("Unsupported command.");
        }
    }
}

/// Decode the command-line tags.  Tags should be of the form key=value, and multiple can be
/// specified, terminated by the command.  It is also possible to specify --tag multiple times.
fn decode_tags<'a, I>(tags: Option<I>) -> StoreTags
where
    I: Iterator<Item = &'a str>,
{
    match tags {
        None => BTreeMap::new(),
        Some(tags) => tags.map(|x| decode_tag(x)).collect(),
    }
}

fn decode_tag<'a>(tag: &'a str) -> (String, String) {
    let fields: Vec<_> = tag.splitn(2, '=').collect();
    if fields.len() != 2 {
        panic!("Tag must be key=value");
    }
    (fields[0].to_string(), fields[1].to_string())
}

/// If the caller doesn't specify a 'name=' tag, generate one based on the current timestamp.
/// Also will add a 'dir' attribute for where the tree was captured.
fn add_name_tag<P: AsRef<Path>>(tags: &mut StoreTags, dir: P) {
    if !tags.contains_key("name") {
        tags.insert("name".to_string(), Local::now().to_rfc3339());
    }

    if !tags.contains_key("dir") {
        tags.insert(
            "dir".to_string(),
            dir.as_ref()
                .canonicalize()
                .unwrap_or_else(|_| Path::new("invalid").to_owned())
                .to_string_lossy()
                .into_owned(),
        );
    }
}

fn dump_versions(versions: &[StoreVersion]) {
    println!("vers | Time captured       | name");
    println!("-----+---------------------+------------------");
    for v in versions {
        let vers = match v.version {
            Version::Latest => "tip",
            Version::Prior => "prev",
            Version::Tagged(ref v) => v,
        };
        println!(
            "{:4} | {} | {}",
            vers,
            v.time.with_timezone(&Local).format("%Y-%m-%d %H:%M:%S"),
            v.name
        );
    }
}
<commit_msg>Change default path to 2sure.weave.gz.<commit_after>// Playing with paths.

extern crate chrono;
extern crate rsure;
extern crate env_logger;
extern crate regex;

#[macro_use]
extern crate log;

#[macro_use]
extern crate clap;

use chrono::Local;
use clap::{App, AppSettings, Arg, SubCommand};

use std::collections::BTreeMap;
use std::path::Path;

use rsure::{show_tree, Progress, SureHash, TreeCompare, stdout_visitor, parse_store, StoreTags,
            StoreVersion, Version};

mod bkcmd;

// For now, just use the crate's error type.
pub use rsure::Result;

#[allow(dead_code)]
fn main() {
    env_logger::init().unwrap();

    let matches = App::new("rsure")
        .version(crate_version!())
        .setting(AppSettings::GlobalVersion)
        .arg(
            Arg::with_name("file")
                .short("f")
                .long("file")
                .takes_value(true)
                .help(
                    "Base of file name, default 2sure, will get .dat.gz appended",
                ),
        )
        .arg(
            Arg::with_name("dir")
                .short("d")
                .long("dir")
                .takes_value(true)
                .help("Directory to scan, defaults to \".\""),
        )
        .arg(
            Arg::with_name("tag")
                .long("tag")
                .takes_value(true)
                .multiple(true)
                .help("key=value to associate with scan"),
        )
        .arg(
            Arg::with_name("version")
                .short("v")
                .long("version")
                .takes_value(true)
                .help("Version of sure data to use (see 'list' output)"),
        )
        .setting(AppSettings::SubcommandRequired)
        .subcommand(SubCommand::with_name("scan").about(
            "Scan a directory for the first time",
        ))
        .subcommand(SubCommand::with_name("update").about(
            "Update the scan using the dat file",
        ))
        .subcommand(SubCommand::with_name("check").about(
            "Compare the directory with the dat file",
        ))
        .subcommand(SubCommand::with_name("signoff").about(
            "Compare the dat file with the bak file",
        ))
        .subcommand(SubCommand::with_name("show").about(
            "Pretty print the dat file",
        ))
        .subcommand(
            SubCommand::with_name("bknew")
                .about("Create a new bitkeeper-based sure store")
                .arg(Arg::with_name("dir").required(true).help(
                    "Directory to create bk-based store",
                )),
        )
        .subcommand(
            SubCommand::with_name("bkimport")
                .about("Import a tree of surefiles into a bk store")
                .arg(
                    Arg::with_name("src")
                        .long("src")
                        .takes_value(true)
                        .required(true),
                )
                .arg(
                    Arg::with_name("dest")
                        .long("dest")
                        .takes_value(true)
                        .required(true),
                ),
        )
        .subcommand(SubCommand::with_name("list").about(
            "List revisions in a given sure store",
        ))
        .get_matches();

    let dir = matches.value_of("dir").unwrap_or(".");

    let file = matches.value_of("file").unwrap_or("2sure.weave.gz");
    let store = parse_store(file).unwrap();

    let mut tags = decode_tags(matches.values_of("tag"));

    add_name_tag(&mut tags, &dir);

    // Note that only the "check" command uses the version tag.
    let latest = match matches.value_of("version") {
        None => Version::Latest,
        Some(x) => Version::Tagged(x.to_string()),
    };

    match matches.subcommand() {
        ("scan", Some(_)) => {
            rsure::update(&dir, &*store, false, &tags).unwrap();
        }
        ("update", Some(_)) => {
            rsure::update(&dir, &*store, true, &tags).unwrap();
        }
        ("check", Some(_)) => {
            let old_tree = store.load(latest).unwrap();
            let mut new_tree = rsure::scan_fs(&dir).unwrap();
            let estimate = new_tree.hash_estimate();
            let pdir = &Path::new(dir);
            let mut progress = Progress::new(estimate.files, estimate.bytes);
            new_tree.hash_update(pdir, &mut progress);
            progress.flush();
            info!("check {:?}", file);
            new_tree.compare_from(&mut stdout_visitor(), &old_tree, pdir);
        }
        ("signoff", Some(_)) => {
            let old_tree = store.load(Version::Prior).unwrap();
            let new_tree = store.load(Version::Latest).unwrap();
            println!("signoff {}", file);
            new_tree.compare_from(&mut stdout_visitor(), &old_tree, &Path::new(dir));
        }
        ("show", Some(_)) => {
            println!("show {}", file);
            show_tree(&Path::new(&file)).unwrap();
        }
        ("bknew", Some(sub)) => {
            let bkdir = sub.value_of("dir").unwrap();
            bkcmd::new(bkdir).unwrap();
        }
        ("bkimport", Some(sub)) => {
            let src = sub.value_of("src").unwrap();
            let dest = sub.value_of("dest").unwrap();
            bkcmd::import(src, dest).unwrap();
        }
        ("list", Some(_)) => {
            let version = store.get_versions().unwrap();
            dump_versions(&version);
        }
        _ => {
            panic!("Unsupported command.");
        }
    }
}

/// Decode the command-line tags.  Tags should be of the form key=value, and multiple can be
/// specified, terminated by the command.  It is also possible to specify --tag multiple times.
fn decode_tags<'a, I>(tags: Option<I>) -> StoreTags
where
    I: Iterator<Item = &'a str>,
{
    match tags {
        None => BTreeMap::new(),
        Some(tags) => tags.map(|x| decode_tag(x)).collect(),
    }
}

fn decode_tag<'a>(tag: &'a str) -> (String, String) {
    let fields: Vec<_> = tag.splitn(2, '=').collect();
    if fields.len() != 2 {
        panic!("Tag must be key=value");
    }
    (fields[0].to_string(), fields[1].to_string())
}

/// If the caller doesn't specify a 'name=' tag, generate one based on the current timestamp.
/// Also will add a 'dir' attribute for where the tree was captured.
fn add_name_tag<P: AsRef<Path>>(tags: &mut StoreTags, dir: P) {
    if !tags.contains_key("name") {
        tags.insert("name".to_string(), Local::now().to_rfc3339());
    }

    if !tags.contains_key("dir") {
        tags.insert(
            "dir".to_string(),
            dir.as_ref()
                .canonicalize()
                .unwrap_or_else(|_| Path::new("invalid").to_owned())
                .to_string_lossy()
                .into_owned(),
        );
    }
}

fn dump_versions(versions: &[StoreVersion]) {
    println!("vers | Time captured       | name");
    println!("-----+---------------------+------------------");
    for v in versions {
        let vers = match v.version {
            Version::Latest => "tip",
            Version::Prior => "prev",
            Version::Tagged(ref v) => v,
        };
        println!(
            "{:4} | {} | {}",
            vers,
            v.time.with_timezone(&Local).format("%Y-%m-%d %H:%M:%S"),
            v.name
        );
    }
}
<|endoftext|>


<commit_before>#[macro_use]
extern crate clap;
extern crate console;
extern crate indicatif;
extern crate syntect;

use clap::{App, Arg, SubCommand};
use console::{style, Emoji};
use indicatif::ProgressBar;
use syntect::easy::HighlightFile;
use syntect::parsing::SyntaxSet;
use syntect::highlighting::{ThemeSet, Style};
use syntect::util::{as_24_bit_terminal_escaped, LinesWithEndings};
use std::fs::remove_file;
use std::io::BufRead;
use std::process::Command;

fn main() {
    let matches = App::new("rustlings")
        .version(crate_version!())
        .author("Olivia Hugger")
        .about("Test")
        .subcommand(SubCommand::with_name("verify").alias("v"))
        .subcommand(
            SubCommand::with_name("run")
                .alias("r")
                .arg(Arg::with_name("file").required(true).index(1)),
        ).get_matches();

    let ss = SyntaxSet::load_defaults_newlines();
    let ts = ThemeSet::load_defaults();

    println!(r#"                 _   _ _                  "#);
    println!(r#"  _ __ _   _ ___| |_| (_)_ __   __ _ ___  "#);
    println!(r#" | '__| | | / __| __| | | '_ \ / _` / __| "#);
    println!(r#" | |  | |_| \__ \ |_| | | | | | (_| \__ \ "#);
    println!(r#" |_|   \__,_|___/\__|_|_|_| |_|\__, |___/ "#);
    println!(r#"                               |___/      "#);
    println!("");

    if let Some(matches) = matches.subcommand_matches("run") {
        if let Some(filename) = matches.value_of("file") {
            let bar = ProgressBar::new_spinner();
            bar.set_message(format!("Compiling {}...", filename).as_str());
            bar.enable_steady_tick(100);
            let compilecmd = Command::new("rustc")
                .args(&[filename, "-o", "temp"])
                .output()
                .expect("fail");
            bar.set_message(format!("Running {}...", filename).as_str());
            if compilecmd.status.success() {
                let runcmd = Command::new("./temp").output().expect("fail");
                bar.finish_and_clear();

                if runcmd.status.success() {
                    println!("{}", String::from_utf8_lossy(&runcmd.stdout));
                    let formatstr =
                        format!("{} Successfully ran {}", Emoji("✅", "✓"), filename);
                    println!("{}", style(formatstr).green());
                    clean().unwrap();
                } else {
                    println!("{}", String::from_utf8_lossy(&runcmd.stdout));
                    println!("{}", String::from_utf8_lossy(&runcmd.stderr));

                    let formatstr =
                        format!("{} Ran {} with errors", Emoji("⚠ ", "!"), filename);
                    println!("{}", style(formatstr).red());
                    clean().unwrap();
                }
            } else {
                bar.finish_and_clear();
                let formatstr = format!(
                    "{} Compilation of {} failed! Compiler error message:\n",
                    Emoji("⚠ ", "!"),
                    filename
                );
                println!("{}", style(formatstr).red());
                println!("{}", String::from_utf8_lossy(&compilecmd.stderr));
                clean().unwrap();
            }
        } else {
            panic!("Please supply a filename!");
        }
    }

    if let Some(_) = matches.subcommand_matches("verify") {
        compile_only("exercises/ex1.rs");
        compile_only("exercises/ex2.rs");
        compile_only("exercises/ex3.rs");
        compile_only("exercises/ex4.rs");
        compile_only("exercises/ex5.rs");

        compile_only("exercises/variables/variables1.rs");
        compile_only("exercises/variables/variables2.rs");
        compile_only("exercises/variables/variables3.rs");
        compile_only("exercises/variables/variables4.rs");

        compile_only("exercises/functions/functions1.rs");
        compile_only("exercises/functions/functions2.rs");
        compile_only("exercises/functions/functions3.rs");
        compile_only("exercises/functions/functions4.rs");
        compile_only("exercises/functions/functions5.rs");

        compile_only("exercises/primitive_types/primitive_types1.rs");
        compile_only("exercises/primitive_types/primitive_types2.rs");
        compile_only("exercises/primitive_types/primitive_types3.rs");
        compile_only("exercises/primitive_types/primitive_types4.rs");
        compile_only("exercises/primitive_types/primitive_types5.rs");
        compile_only("exercises/primitive_types/primitive_types6.rs");

        test("exercises/tests/tests1.rs");
        test("exercises/tests/tests2.rs");
        test("exercises/tests/tests3.rs");
        test("exercises/tests/tests4.rs");

        test("exercises/if/if1.rs");

        compile_only("exercises/strings/strings1.rs");
        compile_only("exercises/strings/strings2.rs");
        compile_only("exercises/strings/strings3.rs");

        compile_only("exercises/move_semantics/move_semantics1.rs");
        compile_only("exercises/move_semantics/move_semantics2.rs");
        compile_only("exercises/move_semantics/move_semantics3.rs");
        compile_only("exercises/move_semantics/move_semantics4.rs");

        compile_only("exercises/modules/modules1.rs");
        compile_only("exercises/modules/modules2.rs");

        compile_only("exercises/macros/macros1.rs");
        compile_only("exercises/macros/macros2.rs");
        compile_only("exercises/macros/macros3.rs");
        compile_only("exercises/macros/macros4.rs");

        test("exercises/error_handling/errors1.rs");
        test("exercises/error_handling/errors2.rs");
        test("exercises/error_handling/errors3.rs");
        test("exercises/error_handling/errorsn.rs");
        compile_only("exercises/error_handling/option1.rs");
        test("exercises/error_handling/result1.rs");
    }

    if let None = matches.subcommand_name() {
        let mut highlighter = HighlightFile::new("default_out.md", &ss, &ts.themes["Solarized (dark)"]).unwrap();
        for maybe_line in highlighter.reader.lines() {
            let line = maybe_line.unwrap();
            let regions: Vec<(Style, &str)> = highlighter.highlight_lines.highlight(&line, &ss);
            println!("{}", as_24_bit_terminal_escaped(&regions[..], true));
        }
    }

    println!("\x1b[0m");
}

fn compile_only(filename: &str) {
    let bar = ProgressBar::new_spinner();
    bar.set_message(format!("Compiling {}...", filename).as_str());
    bar.enable_steady_tick(100);
    let compilecmd = Command::new("rustc")
        .args(&[filename, "-o", "temp", "--color", "always"])
        .output()
        .expect("fail");
    bar.finish_and_clear();
    if compilecmd.status.success() {
        let formatstr = format!(
            "{} Successfully compiled {}!",
            Emoji("✅", "✓"),
            filename
        );
        println!("{}", style(formatstr).green());
        clean().unwrap();
    } else {
        let formatstr = format!(
            "{} Compilation of {} failed! Compiler error message:\n",
            Emoji("⚠ ", "!"),
            filename
        );
        println!("{}", style(formatstr).red());
        println!("{}", String::from_utf8_lossy(&compilecmd.stderr));
        clean().unwrap();
        std::process::exit(1);
    }
}

fn test(filename: &str) {
    let bar = ProgressBar::new_spinner();
    bar.set_message(format!("Testing {}...", filename).as_str());
    bar.enable_steady_tick(100);
    let testcmd = Command::new("rustc")
        .args(&["--test", filename, "-o", "temp"])
        .output()
        .expect("fail");
    bar.finish_and_clear();
    if testcmd.status.success() {
        let formatstr = format!("{} Successfully tested {}!", Emoji("✅", "✓"), filename);
        println!("{}", style(formatstr).green());
        clean().unwrap();
    } else {
        let formatstr = format!(
            "{} Testing of {} failed! Please try again.",
            Emoji("⚠ ", "!"),
            filename
        );
        println!("{}", style(formatstr).red());
        clean().unwrap();
        std::process::exit(1);
    }
}

fn clean() -> Result<(), std::io::Error> {
    remove_file("temp")?;
    Ok(())
}
<commit_msg>switch theme to base16 eighties<commit_after>#[macro_use]
extern crate clap;
extern crate console;
extern crate indicatif;
extern crate syntect;

use clap::{App, Arg, SubCommand};
use console::{style, Emoji};
use indicatif::ProgressBar;
use syntect::easy::HighlightFile;
use syntect::parsing::SyntaxSet;
use syntect::highlighting::{ThemeSet, Style};
use syntect::util::{as_24_bit_terminal_escaped, LinesWithEndings};
use std::fs::remove_file;
use std::io::BufRead;
use std::process::Command;

fn main() {
    let matches = App::new("rustlings")
        .version(crate_version!())
        .author("Olivia Hugger")
        .about("Test")
        .subcommand(SubCommand::with_name("verify").alias("v"))
        .subcommand(
            SubCommand::with_name("run")
                .alias("r")
                .arg(Arg::with_name("file").required(true).index(1)),
        ).get_matches();

    let ss = SyntaxSet::load_defaults_newlines();
    let ts = ThemeSet::load_defaults();

    println!(r#"                 _   _ _                  "#);
    println!(r#"  _ __ _   _ ___| |_| (_)_ __   __ _ ___  "#);
    println!(r#" | '__| | | / __| __| | | '_ \ / _` / __| "#);
    println!(r#" | |  | |_| \__ \ |_| | | | | | (_| \__ \ "#);
    println!(r#" |_|   \__,_|___/\__|_|_|_| |_|\__, |___/ "#);
    println!(r#"                               |___/      "#);
    println!("");

    if let Some(matches) = matches.subcommand_matches("run") {
        if let Some(filename) = matches.value_of("file") {
            let bar = ProgressBar::new_spinner();
            bar.set_message(format!("Compiling {}...", filename).as_str());
            bar.enable_steady_tick(100);
            let compilecmd = Command::new("rustc")
                .args(&[filename, "-o", "temp"])
                .output()
                .expect("fail");
            bar.set_message(format!("Running {}...", filename).as_str());
            if compilecmd.status.success() {
                let runcmd = Command::new("./temp").output().expect("fail");
                bar.finish_and_clear();

                if runcmd.status.success() {
                    println!("{}", String::from_utf8_lossy(&runcmd.stdout));
                    let formatstr =
                        format!("{} Successfully ran {}", Emoji("✅", "✓"), filename);
                    println!("{}", style(formatstr).green());
                    clean().unwrap();
                } else {
                    println!("{}", String::from_utf8_lossy(&runcmd.stdout));
                    println!("{}", String::from_utf8_lossy(&runcmd.stderr));

                    let formatstr =
                        format!("{} Ran {} with errors", Emoji("⚠ ", "!"), filename);
                    println!("{}", style(formatstr).red());
                    clean().unwrap();
                }
            } else {
                bar.finish_and_clear();
                let formatstr = format!(
                    "{} Compilation of {} failed! Compiler error message:\n",
                    Emoji("⚠ ", "!"),
                    filename
                );
                println!("{}", style(formatstr).red());
                println!("{}", String::from_utf8_lossy(&compilecmd.stderr));
                clean().unwrap();
            }
        } else {
            panic!("Please supply a filename!");
        }
    }

    if let Some(_) = matches.subcommand_matches("verify") {
        compile_only("exercises/ex1.rs");
        compile_only("exercises/ex2.rs");
        compile_only("exercises/ex3.rs");
        compile_only("exercises/ex4.rs");
        compile_only("exercises/ex5.rs");

        compile_only("exercises/variables/variables1.rs");
        compile_only("exercises/variables/variables2.rs");
        compile_only("exercises/variables/variables3.rs");
        compile_only("exercises/variables/variables4.rs");

        compile_only("exercises/functions/functions1.rs");
        compile_only("exercises/functions/functions2.rs");
        compile_only("exercises/functions/functions3.rs");
        compile_only("exercises/functions/functions4.rs");
        compile_only("exercises/functions/functions5.rs");

        compile_only("exercises/primitive_types/primitive_types1.rs");
        compile_only("exercises/primitive_types/primitive_types2.rs");
        compile_only("exercises/primitive_types/primitive_types3.rs");
        compile_only("exercises/primitive_types/primitive_types4.rs");
        compile_only("exercises/primitive_types/primitive_types5.rs");
        compile_only("exercises/primitive_types/primitive_types6.rs");

        test("exercises/tests/tests1.rs");
        test("exercises/tests/tests2.rs");
        test("exercises/tests/tests3.rs");
        test("exercises/tests/tests4.rs");

        test("exercises/if/if1.rs");

        compile_only("exercises/strings/strings1.rs");
        compile_only("exercises/strings/strings2.rs");
        compile_only("exercises/strings/strings3.rs");

        compile_only("exercises/move_semantics/move_semantics1.rs");
        compile_only("exercises/move_semantics/move_semantics2.rs");
        compile_only("exercises/move_semantics/move_semantics3.rs");
        compile_only("exercises/move_semantics/move_semantics4.rs");

        compile_only("exercises/modules/modules1.rs");
        compile_only("exercises/modules/modules2.rs");

        compile_only("exercises/macros/macros1.rs");
        compile_only("exercises/macros/macros2.rs");
        compile_only("exercises/macros/macros3.rs");
        compile_only("exercises/macros/macros4.rs");

        test("exercises/error_handling/errors1.rs");
        test("exercises/error_handling/errors2.rs");
        test("exercises/error_handling/errors3.rs");
        test("exercises/error_handling/errorsn.rs");
        compile_only("exercises/error_handling/option1.rs");
        test("exercises/error_handling/result1.rs");
    }

    if let None = matches.subcommand_name() {
        let mut highlighter = HighlightFile::new("default_out.md", &ss, &ts.themes["base16-eighties.dark"]).unwrap();
        for maybe_line in highlighter.reader.lines() {
            let line = maybe_line.unwrap();
            let regions: Vec<(Style, &str)> = highlighter.highlight_lines.highlight(&line, &ss);
            println!("{}", as_24_bit_terminal_escaped(&regions[..], true));
        }
    }

    println!("\x1b[0m");
}

fn compile_only(filename: &str) {
    let bar = ProgressBar::new_spinner();
    bar.set_message(format!("Compiling {}...", filename).as_str());
    bar.enable_steady_tick(100);
    let compilecmd = Command::new("rustc")
        .args(&[filename, "-o", "temp", "--color", "always"])
        .output()
        .expect("fail");
    bar.finish_and_clear();
    if compilecmd.status.success() {
        let formatstr = format!(
            "{} Successfully compiled {}!",
            Emoji("✅", "✓"),
            filename
        );
        println!("{}", style(formatstr).green());
        clean().unwrap();
    } else {
        let formatstr = format!(
            "{} Compilation of {} failed! Compiler error message:\n",
            Emoji("⚠ ", "!"),
            filename
        );
        println!("{}", style(formatstr).red());
        println!("{}", String::from_utf8_lossy(&compilecmd.stderr));
        clean().unwrap();
        std::process::exit(1);
    }
}

fn test(filename: &str) {
    let bar = ProgressBar::new_spinner();
    bar.set_message(format!("Testing {}...", filename).as_str());
    bar.enable_steady_tick(100);
    let testcmd = Command::new("rustc")
        .args(&["--test", filename, "-o", "temp"])
        .output()
        .expect("fail");
    bar.finish_and_clear();
    if testcmd.status.success() {
        let formatstr = format!("{} Successfully tested {}!", Emoji("✅", "✓"), filename);
        println!("{}", style(formatstr).green());
        clean().unwrap();
    } else {
        let formatstr = format!(
            "{} Testing of {} failed! Please try again.",
            Emoji("⚠ ", "!"),
            filename
        );
        println!("{}", style(formatstr).red());
        clean().unwrap();
        std::process::exit(1);
    }
}

fn clean() -> Result<(), std::io::Error> {
    remove_file("temp")?;
    Ok(())
}
<|endoftext|>


<commit_before>#[derive(Clone)]
enum PBType {
    Double,
    Float,
    Int32,
    Int64,
    Uint32,
    Uint64,
    Sint32,
    sInt64,
    Fixed32,
    Fixed64,
    Sfixed32,
    Sfixed64,
    Bool,
    String,
    Bytes,
}

struct PBField {
    name: String,
    tag: u8,
    field_type: PBType,
}

struct PBMessage {
    name: String,
    fields: Vec<PBField>,
}

#[derive(Debug)]
#[derive(Clone)]
enum PBWireType {
    VarInt,
    Fixed64,
    LengthDelim,
    Fixed32,
    Reserved,
}

struct TagValue {
    tag: u8,
    value: Vec<u8>,
}

#[derive(Clone)]
struct ParserPosition {
    position: usize,
    tag: u8,
    wire_type: PBWireType,
    cur_idx: u8,
    max_idx: u8,
}

fn PBParseNext(s: Vec<u8>, pos: ParserPosition) -> (TagValue, ParserPosition) {
    let idx2wireType = vec![PBWireType::VarInt,
                            PBWireType::Fixed64,
                            PBWireType::LengthDelim,
                            PBWireType::Reserved,
                            PBWireType::Reserved,
                            PBWireType::Fixed32];

    let mut p = pos.clone();

    if p.cur_idx == p.max_idx {
        p.tag = s[p.position] >> 3;
        p.wire_type = idx2wireType[(s[p.position] & 7) as usize].clone();
        p.position += 1;
        p.cur_idx = 0;
        p.max_idx = 0;
    }
    let mut value = match p.wire_type {
        PBWireType::LengthDelim => {
            let offset = s[p.position] as usize;
            let start = p.position + 1;
            let end = p.position + offset;
            p.position = end + 1;
            &s[start..end + 1]
        }
        _ => &[],
    };
    let mut v = Vec::new();
    v.extend_from_slice(value);
    (TagValue {
         value: v.clone(),
         tag: p.tag,
     },
     p.clone())
}

fn PBBytesToString(field_type: PBType, bytes: Vec<u8>) -> String {
    match field_type {
        PBType::String => String::from_utf8(bytes).unwrap(),
        _ => String::from("Not Implemented"),
    }
}

fn main() {
    let field = PBField {
        name: String::from("b"),
        tag: 2,
        field_type: PBType::String,
    };
    let msg = PBMessage {
        name: String::from("Test2"),
        fields: vec![field],
    };

    let msg = vec![0x12, 0x07, 0x74, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x67];

    let (x, pp) = PBParseNext(msg,
                              ParserPosition {
                                  position: 0,
                                  tag: 0,
                                  wire_type: PBWireType::Reserved,
                                  cur_idx: 0,
                                  max_idx: 0,
                              });

    print!("Tag   = {}\n", x.tag);
    print!("Value = {}\n", String::from_utf8(x.value).unwrap());
}
<commit_msg>Cleanup to ask for help<commit_after>#[derive(Debug)]
#[derive(Clone)]
enum PBWireType {
    VarInt,
    Fixed64,
    LengthDelim,
    Fixed32,
    Reserved,
}

struct TagValue<'a> {
    tag: u8,
    value: &'a [u8],
}

#[derive(Clone)]
struct ParserPosition {
    position: usize,
    tag: u8,
    wire_type: PBWireType,
    cur_idx: u8,
    max_idx: u8,
}

fn PBParseNext<'a>(s: &'a [u8], pos: ParserPosition) -> (TagValue<'a>, ParserPosition) {
    let idx2wireType = vec![PBWireType::VarInt,
                            PBWireType::Fixed64,
                            PBWireType::LengthDelim,
                            PBWireType::Reserved,
                            PBWireType::Reserved,
                            PBWireType::Fixed32];

    let mut p = pos.clone();

    if p.cur_idx == p.max_idx {
        p.tag = s[p.position] >> 3;
        p.wire_type = idx2wireType[(s[p.position] & 7) as usize].clone();
        p.position += 1;
        p.cur_idx = 0;
        p.max_idx = 0;
    }
    let mut value = match p.wire_type {
        PBWireType::LengthDelim => {
            let offset = s[p.position] as usize;
            let start = p.position + 1;
            let end = p.position + offset;
            p.position = end + 1;
            &s[start..end + 1]
        }
        _ => &[],
    };
    (TagValue {
         value: value,
         tag: p.tag,
     },
     p.clone())
}

use std::str;

fn main() {
    let msg = vec![0x12, 0x07, 0x74, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x67];

    let (x, pp) = PBParseNext(msg.as_slice(),
                              ParserPosition {
                                  position: 0,
                                  tag: 0,
                                  wire_type: PBWireType::Reserved,
                                  cur_idx: 0,
                                  max_idx: 0,
                              });

    print!("Tag   = {}\n", x.tag);
    print!("Value = {}\n", str::from_utf8(x.value).unwrap());
}
<|endoftext|>