<commit_before>extern crate rustyline;
extern crate serde;
extern crate serde_json;
use rustyline::Editor;
use rustyline::error::ReadlineError;
use rustyline::completion::Completer;
use std::env::args;
use std::path::PathBuf;
use std::process::Command;
use std::env::home_dir;
use std::fs::create_dir;
use std::fs::File;
use std::collections::HashMap;

struct BashCompleter{
    command: String,
}

impl Completer for BashCompleter {
    fn complete(&self, line: &str, pos: usize) -> rustyline::Result<(usize, Vec<String>)> {
        let words: Vec<&str> = line.split(" ").collect();
        let last_word = words.iter().nth(words.len()-1).unwrap();
        let count_words = words.len();

        let script = format!(
                    // COMP_WORDS must be specified in a bash context because normal environment
                    // variables can't be arrays
                    "
                    COMP_CWORD={}
                    COMP_POINT={}
                    COMP_LINE=\"{} {}\"
                    COMP_WORDS=({} {})
                    _xfunc git _git
                    printf \"%s\\n\" \"${{COMPREPLY[@]}}\"
                    ",
                    count_words,
                    pos + self.command.len() + 1,
                    self.command,
                    line,
                    self.command,
                    line,
                );
        let completion_result = Command::new("bash")
            .args(vec![
                "-lic",
                script.as_str(),
            ])
            .output();
        let completion_str = match completion_result {
            Ok(completion_string) => String::from_utf8(completion_string.stdout).unwrap(),
            Err(err) => {
                return Err(ReadlineError::Io(err));
            },
        };

        let word_len = last_word.len();
        let completions: Vec<String> = completion_str.split("\n").map(|s| s.to_string()).collect();

        Ok((pos-word_len, completions))
    }
}

fn main() {
    // TODO use a real arg parser
    let program = args().nth(1).expect("no program specified");

    let mut line_editor = Editor::<BashCompleter>::new();
    line_editor.set_completer(Some(BashCompleter{command: program.to_string()}));

    let (history_file_option, prompts_config_path_option) = match home_dir() {
        Some(home) => {
            let config_dir: PathBuf = [home, PathBuf::from(".tpol")].iter().collect();
            if !config_dir.exists() {
                println!("creating config dir at {}", config_dir.to_str().unwrap());
                create_dir(&config_dir).unwrap();
            }

            (
                {
                    let history_dir: PathBuf = [&config_dir, &PathBuf::from("history")].iter().collect();
                    if !history_dir.exists() {
                        println!("creating history dir at {}", history_dir.to_str().unwrap());
                        create_dir(&history_dir).unwrap();
                    }

                    let command_history: PathBuf = [history_dir, PathBuf::from(&program)].iter().collect();
                    if !command_history.exists() {
                        println!("creating history file for {} at {}", &program, command_history.to_str().unwrap());
                        let _ = File::create(&command_history).unwrap();
                    }

                    Some(command_history)
                },
                {
                    let prompts_config_path: PathBuf = [&config_dir, &PathBuf::from("prompts.json")].iter().collect();
                    Some(prompts_config_path)
                },
            )
        }
        None => (None, None)
    };

    if let Some(ref history_file) = history_file_option.clone() {
        if let Err(err) = line_editor.load_history(history_file) {
            eprintln!("Warning: error while trying to load history file {}: {}", history_file.to_str().unwrap(), err);
        }
    } else {
        eprintln!("Warning: can't find home directory, no history will be saved");
    }

    let program_to_prompt_string_command = match prompts_config_path_option {
        Some(prompts_config_path) => {
            File::open(prompts_config_path)
                .map(|file| {
                    let prompts_config: HashMap<String, String> = serde_json::from_reader(file)
                        .unwrap_or(HashMap::new());
                    prompts_config
                })
                .unwrap_or(HashMap::new())
        }
        None => HashMap::new(),
    };

    let prompt_string_command_option = program_to_prompt_string_command.get(&program);

    loop {
        let prompt_string = match prompt_string_command_option.as_ref() {
            Some(ref command) => {
                match Command::new("bash").args(vec!["-lic", command]).output() {
                    Ok(output) => String::from_utf8(output.stdout).unwrap(),
                    Err(_) => {
                        // TODO log error
                        "".to_string()
                    }
                }
            },
            None => "".to_string(),
        };

        let line_result = line_editor.readline(format!("{}>{} ", prompt_string, &program).as_str());
        match line_result {
            Ok(line) => {
                match line.as_ref() {
                    "" => {}, // ignore empty commands
                    _ => {
                        let mut process_result = Command::new(&program)
                            // TODO deal with quoted strings
                            .args(line.split(" ").collect::<Vec<&str>>())
                            .spawn();
                        match process_result {
                            Ok(mut process) => {
                                // TODO maybe display return code?
                                let _ = process.wait();
                                // TODO maybe only save in history if it's successful?
                                line_editor.add_history_entry(&line);
                            },
                            Err(err) => println!("error while trying to run command: {:?}", err),
                        }
                    }
                }
            },
            Err(ReadlineError::Interrupted) => {
                break;
            },
            Err(ReadlineError::Eof) => {
                break;
            },
            Err(err) => {
                eprintln!("{:?}", err);
                break;
            }
        }
    }

    if let Some(ref history_file) = history_file_option {
        if let Err(err) = line_editor.save_history(history_file) {
            eprintln!("Warning: error while trying to load history file {}: {}", history_file.to_str().unwrap(), err);
        }
    }
}
<commit_msg>add support for escaping with !<commit_after>extern crate rustyline;
extern crate serde;
extern crate serde_json;
use rustyline::Editor;
use rustyline::error::ReadlineError;
use rustyline::completion::Completer;
use std::env::args;
use std::path::PathBuf;
use std::process::Command;
use std::env::home_dir;
use std::fs::create_dir;
use std::fs::File;
use std::collections::HashMap;

struct BashCompleter{
    command: String,
}

impl Completer for BashCompleter {
    fn complete(&self, line: &str, pos: usize) -> rustyline::Result<(usize, Vec<String>)> {
        let words: Vec<&str> = line.split(" ").collect();
        let last_word = words.iter().nth(words.len()-1).unwrap();
        let count_words = words.len();

        let script = format!(
                    // COMP_WORDS must be specified in a bash context because normal environment
                    // variables can't be arrays
                    "
                    COMP_CWORD={}
                    COMP_POINT={}
                    COMP_LINE=\"{} {}\"
                    COMP_WORDS=({} {})
                    _xfunc git _git
                    printf \"%s\\n\" \"${{COMPREPLY[@]}}\"
                    ",
                    count_words,
                    pos + self.command.len() + 1,
                    self.command,
                    line,
                    self.command,
                    line,
                );
        let completion_result = Command::new("bash")
            .args(vec![
                "-lic",
                script.as_str(),
            ])
            .output();
        let completion_str = match completion_result {
            Ok(completion_string) => String::from_utf8(completion_string.stdout).unwrap(),
            Err(err) => {
                return Err(ReadlineError::Io(err));
            },
        };

        let word_len = last_word.len();
        let completions: Vec<String> = completion_str.split("\n").map(|s| s.to_string()).collect();

        Ok((pos-word_len, completions))
    }
}

fn main() {
    // TODO use a real arg parser
    let program = args().nth(1).expect("no program specified");

    let mut line_editor = Editor::<BashCompleter>::new();
    line_editor.set_completer(Some(BashCompleter{command: program.to_string()}));

    let (history_file_option, prompts_config_path_option) = match home_dir() {
        Some(home) => {
            let config_dir: PathBuf = [home, PathBuf::from(".tpol")].iter().collect();
            if !config_dir.exists() {
                println!("creating config dir at {}", config_dir.to_str().unwrap());
                create_dir(&config_dir).unwrap();
            }

            (
                {
                    let history_dir: PathBuf = [&config_dir, &PathBuf::from("history")].iter().collect();
                    if !history_dir.exists() {
                        println!("creating history dir at {}", history_dir.to_str().unwrap());
                        create_dir(&history_dir).unwrap();
                    }

                    let command_history: PathBuf = [history_dir, PathBuf::from(&program)].iter().collect();
                    if !command_history.exists() {
                        println!("creating history file for {} at {}", &program, command_history.to_str().unwrap());
                        let _ = File::create(&command_history).unwrap();
                    }

                    Some(command_history)
                },
                {
                    let prompts_config_path: PathBuf = [&config_dir, &PathBuf::from("prompts.json")].iter().collect();
                    Some(prompts_config_path)
                },
            )
        }
        None => (None, None)
    };

    if let Some(ref history_file) = history_file_option.clone() {
        if let Err(err) = line_editor.load_history(history_file) {
            eprintln!("Warning: error while trying to load history file {}: {}", history_file.to_str().unwrap(), err);
        }
    } else {
        eprintln!("Warning: can't find home directory, no history will be saved");
    }

    let program_to_prompt_string_command = match prompts_config_path_option {
        Some(prompts_config_path) => {
            File::open(prompts_config_path)
                .map(|file| {
                    let prompts_config: HashMap<String, String> = serde_json::from_reader(file)
                        .unwrap_or(HashMap::new());
                    prompts_config
                })
                .unwrap_or(HashMap::new())
        }
        None => HashMap::new(),
    };

    let prompt_string_command_option = program_to_prompt_string_command.get(&program);

    loop {
        let prompt_string = match prompt_string_command_option.as_ref() {
            Some(ref command) => {
                match Command::new("bash").args(vec!["-lic", command]).output() {
                    Ok(output) => String::from_utf8(output.stdout).unwrap(),
                    Err(_) => {
                        // TODO log error
                        "".to_string()
                    }
                }
            },
            None => "".to_string(),
        };

        let line_result = line_editor.readline(format!("{}>{} ", prompt_string, &program).as_str());
        match line_result {
            Ok(line) => {
                if line == "" || line == "!" {
                    // ignore empty commands
                } else {
                    let mut command = if line.starts_with("!") {
                        let parts = line.split(" ");
                        let command = &parts.clone().nth(0).unwrap()[1..];
                        let args: Vec<&str> = parts.skip(1).collect();
                        println!("{} {:?}", command, args);
                        let mut command = Command::new(command);
                        command.args(args);
                        command
                    } else {
                        let mut command = Command::new(&program);
                        // TODO deal with quoted strings
                        command.args(line.split(" ").collect::<Vec<&str>>());
                        command
                    };
                    let mut process_result = command.spawn();
                    match process_result {
                        Ok(mut process) => {
                            // TODO maybe display return code?
                            let _ = process.wait();
                            // TODO maybe only save in history if it's successful?
                            line_editor.add_history_entry(&line);
                        },
                        Err(err) => println!("error while trying to run command: {:?}", err),
                    }
                }
            },
            Err(ReadlineError::Interrupted) => {
                break;
            },
            Err(ReadlineError::Eof) => {
                break;
            },
            Err(err) => {
                eprintln!("{:?}", err);
                break;
            }
        }
    }

    if let Some(ref history_file) = history_file_option {
        if let Err(err) = line_editor.save_history(history_file) {
            eprintln!("Warning: error while trying to load history file {}: {}", history_file.to_str().unwrap(), err);
        }
    }
}
<|endoftext|>


<commit_before>// Copyright 2016 rust-fuzz developers
//
// Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or
// http://apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT or
// http://opensource.org/licenses/MIT>, at your option. This file may not be
// copied, modified, or distributed except according to those terms.

extern crate cargo_metadata;
extern crate clap;
extern crate rustc_serialize;
extern crate term;

use cargo_metadata::{metadata, Package};
use clap::{App, Arg};
use std::{convert, env, error, fmt, fs, io, path, process};
use std::io::Write;

mod utils;

const VERSION: Option<&'static str> = option_env!("CARGO_PKG_VERSION");

fn main() {
    let app = App::new("cargo-fuzz")
        .version(VERSION.unwrap_or("unknown"))
        .arg(Arg::with_name("init")
            .long("init")
            .help("Initialize fuzz folder"))
        .arg(Arg::with_name("fuzz-target")
            .long("fuzz-target")
            .value_name("TARGET")
            .help("Run with given fuzz target in fuzz/fuzzers")
            .takes_value(true))
        .arg(Arg::with_name("add")
            .long("add")
            .value_name("TARGET")
            .help("Add a new fuzz target")
            .takes_value(true))
        .arg(Arg::with_name("list")
            .long("list")
             .help("List the available fuzz targets"));
    let mut app_help = Vec::new();
    app.write_help(&mut app_help).ok().expect("could not write help");
    let args = app.get_matches();

    let result = if args.is_present("init") {
        init_fuzz()
    } else if let Some(target) = args.value_of("add") {
        add_target(target)
    } else if let Some(target) = args.value_of("fuzz-target") {
        let result = run_target(target);
        if let Ok(success) = result {
            if success {
                // Can this ever happen?
                Ok(())
            } else {
                utils::print_message("Fuzzing found errors!", term::color::YELLOW);
                process::exit(-1)
            }
        } else {
            result.map(|_| ())
        }
    } else if args.is_present("list") {
        list_fuzz_targets()
            .map(|_| ())
    } else {
        println!("Invalid arguments. Usage:\n{}",
                 String::from_utf8(app_help).expect("help not utf8!"));
        return;
    };
    if let Err(error) = result {
        utils::write_to_stderr(error.description(), None);
    }
}

fn list_fuzz_targets() -> Result<(), Box<error::Error>> {
    if !path::Path::new("./fuzz").is_dir() {
        return Err("Fuzzing crate has not been initialized. Run `cargo fuzz --init` to initialize it.".into());
    }

    env::set_current_dir("./fuzz")?;
    let package = get_package();
    for target in &package.targets {
        utils::print_message(target.name.as_str(), term::color::GREEN);
    }

    Ok(())
}

/// Create all the files and folders we need to run
///
/// This will not clone libfuzzer-sys
fn init_fuzz() -> Result<(), Box<error::Error>> {
    let me = get_package();

    fs::create_dir("./fuzz")?;
    fs::create_dir("./fuzz/fuzzers")?;

    let mut cargo = fs::File::create(path::Path::new("./fuzz/Cargo.toml"))?;

write!(cargo, r#"
[package]
name = "{0}-fuzz"
version = "0.0.1"
authors = ["Automatically generated"]
publish = false

[dependencies.{0}]
path = ".."

# Prevent this from interfering with workspaces
[workspace]
members = ["."]

[[bin]]
name = "fuzzer_script_1"
path = "fuzzers/fuzzer_script_1.rs"
"#, me.name)?;

    let mut ignore = fs::File::create(path::Path::new("./fuzz/.gitignore"))?;

write!(ignore, r#"
target
libfuzzer
corpus
artifacts
"#)?;

    let mut script = fs::File::create(path::Path::new("./fuzz/fuzzers/fuzzer_script_1.rs"))?;
    dummy_target(&mut script, &me)
}

/// Returns metadata for the Cargo package in the current directory
fn get_package() -> Package {
    // todo error handling
    let meta = metadata(None).unwrap();
    let mut p = env::current_dir().unwrap();
    p.push("Cargo.toml");
    let p = p.to_str().unwrap();
    meta.packages.into_iter().find(|package| package.manifest_path == p).unwrap()
}

/// If the package contains a library target, generate an `extern crate` line to link to it.
fn link_to_lib(pkg: &Package) -> Option<String> {
    pkg.targets.iter()
               .find(|target| target.kind.iter().any(|k| k == "lib"))
               .map(|target| format!("extern crate {};\n", target.name.replace("-", "_")))
}

/// Create a dummy fuzz target script at the given path
fn dummy_target(script: &mut fs::File, pkg: &Package) -> Result<(), Box<error::Error>> {
write!(script, r#"#![no_main]
extern crate libfuzzer_sys;
{}
#[export_name="rust_fuzzer_test_input"]
pub extern fn go(data: &[u8]) {{
    // fuzzed code goes here
}}"#, link_to_lib(pkg).unwrap_or(String::new())).map_err(|e| e.into())
}

/// Add a new fuzz target script with a given name
fn add_target<S>(target: S) -> Result<(), Box<error::Error>> where S: Into<String> + fmt::Display {
    let target_file = format!("fuzz/fuzzers/{}.rs", target);
    let mut script = fs::File::create(path::Path::new(&target_file))?;
    let me = get_package();
    dummy_target(&mut script, &me)?;

    let mut cargo = fs::OpenOptions::new().append(true).open(path::Path::new("./fuzz/Cargo.toml"))?;

write!(cargo, r#"
[[bin]]
name = "{0}"
path = "fuzzers/{0}.rs"
"#, target).map_err(|e| e.into())

}

/// Build or rebuild libFuzzer (rebuilds only if the compiler version changed)
///
/// We can't just use libFuzzer as a dependency since libgcc will
/// get compiled with sanitizer support. RUSTFLAGS does not discriminate
/// between build dependencies and regular ones.
///
/// https://github.com/rust-lang/cargo/issues/3739
fn rebuild_libfuzzer() -> Result<(), Box<error::Error>> {
    if let Err(_) = env::set_current_dir("./libfuzzer") {
        let mut git = process::Command::new("git");
        let mut cmd = git.arg("clone")
                         .arg("https://github.com/rust-fuzz/libfuzzer-sys.git")
                         .arg("libfuzzer");
        let result = cmd.spawn()?.wait()?;
        if !result.success() {
            return Err("Failed to clone libfuzzer-sys".into())
        }
        env::set_current_dir("./libfuzzer")?;
    }
    let mut cmd = process::Command::new("cargo");
    cmd.arg("build")
       .arg("--release")
       .spawn()?
       .wait()?;

    let result = cmd.spawn()?.wait()?;
    if !result.success() {
        return Err("Failed to build libfuzzer-sys".into())
    }
    env::set_current_dir("..")
        .map_err(|e| e.into())
}

fn make_dir_if_not_exist(dir: &str) -> Result<(), io::Error> {
    if let Err(k) = fs::create_dir(dir) {
        if k.kind() == io::ErrorKind::AlreadyExists {
            // do nothing
        } else {
            return Err(k);
        }
    }
    Ok(())
}
/// Fuzz a given fuzz target
fn run_target<S>(target: S) -> Result<bool, Box<error::Error>> where S: Into<String> + fmt::Display + convert::AsRef<std::ffi::OsStr> {
    env::set_current_dir("./fuzz")?;
    rebuild_libfuzzer()?;
    let mut flags = env::var("RUSTFLAGS").unwrap_or("".into());
    if !flags.is_empty() {
        flags.push(' ');
    }
    flags.push_str("-Cpasses=sancov -Cllvm-args=-sanitizer-coverage-level=3 -Zsanitizer=address -Cpanic=abort");
    let mut cmd = process::Command::new("cargo");
    cmd.arg("rustc")
       .arg("--verbose")
       .arg("--bin")
       .arg(&target)
       .arg("--target")
       .arg("x86_64-unknown-linux-gnu") // won't pass rustflags to build scripts
       .arg("--")
       .arg("-L")
       .arg("libfuzzer/target/release")
       .env("RUSTFLAGS", &flags);

    let result = cmd.spawn()?.wait()?;
    if !result.success() {
        return Err("Failed to build fuzz target".into())
    }

    make_dir_if_not_exist("corpus")?;
    make_dir_if_not_exist("artifacts")?;

    // can't use cargo run since we can't pass -L args to it
    let path = format!("target/debug/{}", target);
    let mut run_cmd = process::Command::new(path);
    run_cmd.arg("-artifact_prefix=artifacts/")
           .arg("corpus") // must be last arg
           .env("ASAN_OPTIONS", "detect_odr_violation=0");
    let result = run_cmd.spawn()?.wait()?;
    Ok(result.success())
}
<commit_msg>Move to clap subcommands<commit_after>// Copyright 2016 rust-fuzz developers
//
// Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or
// http://apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT or
// http://opensource.org/licenses/MIT>, at your option. This file may not be
// copied, modified, or distributed except according to those terms.

extern crate cargo_metadata;
extern crate clap;
extern crate rustc_serialize;
extern crate term;

use cargo_metadata::{metadata, Package};
use clap::{App, Arg, SubCommand, ArgMatches, AppSettings};
use std::{env, error, fs, io, path, process};
use std::io::Write;

mod utils;

const VERSION: Option<&'static str> = option_env!("CARGO_PKG_VERSION");

fn main() {
    let app = App::new("cargo-fuzz")
        .version(VERSION.unwrap_or("unknown"))
        .setting(AppSettings::SubcommandRequired)
        .subcommand(SubCommand::with_name("init").about("Initialize the fuzz folder"))
        .subcommand(SubCommand::with_name("run").about("Run the fuzz target in fuzz/fuzzers")
                    .arg(Arg::with_name("TARGET").required(true)))
        .subcommand(SubCommand::with_name("add").about("Add a new fuzz target")
                    .arg(Arg::with_name("TARGET").required(true)))
        .subcommand(SubCommand::with_name("list").about("List all fuzz targets"));
    let args = app.get_matches();

    ::std::process::exit(match args.subcommand() {
        ("init", _) => init_fuzz(),
        ("add", matches) => add_target(matches.expect("arguments present")),
        ("list", _) => list_targets(),
        ("run", matches) => exec_target(matches.expect("arguments present")),
        (s, _) => panic!("unimplemented subcommand {}!", s),
    }.map(|_| 0).unwrap_or_else(|err| {
        writeln!(io::stderr(), "Error: {}", err).expect("failed writing to stderr");
        1
    }));
}

/// Create all the files and folders we need to run
///
/// This will not clone libfuzzer-sys
fn init_fuzz() -> Result<(), Box<error::Error>> {
    let me = get_package();

    fs::create_dir("./fuzz")?;
    fs::create_dir("./fuzz/fuzzers")?;

    let mut cargo = fs::File::create(path::Path::new("./fuzz/Cargo.toml"))?;

write!(cargo, r#"
[package]
name = "{0}-fuzz"
version = "0.0.1"
authors = ["Automatically generated"]
publish = false

[dependencies.{0}]
path = ".."

# Prevent this from interfering with workspaces
[workspace]
members = ["."]

[[bin]]
name = "fuzzer_script_1"
path = "fuzzers/fuzzer_script_1.rs"
"#, me.name)?;

    let mut ignore = fs::File::create(path::Path::new("./fuzz/.gitignore"))?;

write!(ignore, r#"
target
libfuzzer
corpus
artifacts
"#)?;

    let mut script = fs::File::create(path::Path::new("./fuzz/fuzzers/fuzzer_script_1.rs"))?;
    dummy_target(&mut script, &me)
}

fn list_targets() -> Result<(), Box<error::Error>> {
    if !path::Path::new("./fuzz").is_dir() {
        return Err("Fuzzing has not been initialized. Run `cargo fuzz init` first.".into());
    }
    env::set_current_dir("./fuzz")?;
    let package = get_package();
    for target in &package.targets {
        println!("{}", target.name);
    }
    Ok(())
}

/// Returns metadata for the Cargo package in the current directory
fn get_package() -> Package {
    // todo error handling
    let meta = metadata(None).unwrap();
    let mut p = env::current_dir().unwrap();
    p.push("Cargo.toml");
    let p = p.to_str().unwrap();
    meta.packages.into_iter().find(|package| package.manifest_path == p).unwrap()
}

/// If the package contains a library target, generate an `extern crate` line to link to it.
fn link_to_lib(pkg: &Package) -> Option<String> {
    pkg.targets.iter()
               .find(|target| target.kind.iter().any(|k| k == "lib"))
               .map(|target| format!("extern crate {};\n", target.name.replace("-", "_")))
}

/// Create a dummy fuzz target script at the given path
fn dummy_target(script: &mut fs::File, pkg: &Package) -> Result<(), Box<error::Error>> {
write!(script, r#"#![no_main]
extern crate libfuzzer_sys;
{}
#[export_name="rust_fuzzer_test_input"]
pub extern fn go(data: &[u8]) {{
    // fuzzed code goes here
}}"#, link_to_lib(pkg).unwrap_or(String::new())).map_err(|e| e.into())
}

/// Add a new fuzz target script with a given name
fn add_target<'a>(args: &ArgMatches<'a>) -> Result<(), Box<error::Error>> {
    let target: String = args.value_of_os("TARGET").expect("TARGET is required").to_os_string()
        .into_string().map_err(|_| "TARGET must be valid unicode")?;
    let components: &[&path::Path] = &["fuzz".as_ref(), "fuzzers".as_ref(), target.as_ref()];
    let target_file = components.iter().collect::<path::PathBuf>();
    let mut script = fs::File::create(path::Path::new(&target_file))?;
    let me = get_package();
    dummy_target(&mut script, &me)?;

    let mut cargo = fs::OpenOptions::new().append(true).open(path::Path::new("./fuzz/Cargo.toml"))?;

write!(cargo, r#"
[[bin]]
name = "{0}"
path = "fuzzers/{0}.rs"
"#, target).map_err(|e| e.into())

}

/// Build or rebuild libFuzzer (rebuilds only if the compiler version changed)
///
/// We can't just use libFuzzer as a dependency since libgcc will
/// get compiled with sanitizer support. RUSTFLAGS does not discriminate
/// between build dependencies and regular ones.
///
/// https://github.com/rust-lang/cargo/issues/3739
fn rebuild_libfuzzer() -> Result<(), Box<error::Error>> {
    if let Err(_) = env::set_current_dir("./libfuzzer") {
        let mut git = process::Command::new("git");
        let mut cmd = git.arg("clone")
                         .arg("https://github.com/rust-fuzz/libfuzzer-sys.git")
                         .arg("libfuzzer");
        let result = cmd.spawn()?.wait()?;
        if !result.success() {
            return Err("Failed to clone libfuzzer-sys".into())
        }
        env::set_current_dir("./libfuzzer")?;
    }
    let mut cmd = process::Command::new("cargo");
    cmd.arg("build")
       .arg("--release")
       .spawn()?
       .wait()?;

    let result = cmd.spawn()?.wait()?;
    if !result.success() {
        return Err("Failed to build libfuzzer-sys".into())
    }
    env::set_current_dir("..")
        .map_err(|e| e.into())
}

fn make_dir_if_not_exist(dir: &str) -> Result<(), io::Error> {
    if let Err(k) = fs::create_dir(dir) {
        if k.kind() == io::ErrorKind::AlreadyExists {
            // do nothing
        } else {
            return Err(k);
        }
    }
    Ok(())
}
/// Fuzz a given fuzz target
fn exec_target<'a>(args: &ArgMatches<'a>) -> Result<(), Box<error::Error>> {
    let target: String = args.value_of_os("TARGET").expect("TARGET is required").to_os_string()
        .into_string().map_err(|_| "TARGET must be valid unicode")?;

    env::set_current_dir("./fuzz")?;
    rebuild_libfuzzer()?;
    let mut flags = env::var("RUSTFLAGS").unwrap_or("".into());
    if !flags.is_empty() {
        flags.push(' ');
    }
    flags.push_str("-Cpasses=sancov -Cllvm-args=-sanitizer-coverage-level=3 -Zsanitizer=address -Cpanic=abort");
    let mut cmd = process::Command::new("cargo");
    cmd.arg("rustc")
       .arg("--verbose")
       .arg("--bin")
       .arg(&target)
       .arg("--target")
       .arg("x86_64-unknown-linux-gnu") // won't pass rustflags to build scripts
       .arg("--")
       .arg("-L")
       .arg("libfuzzer/target/release")
       .env("RUSTFLAGS", &flags);

    let result = cmd.spawn()?.wait()?;
    if !result.success() {
        return Err("Failed to build fuzz target".into())
    }

    make_dir_if_not_exist("corpus")?;
    make_dir_if_not_exist("artifacts")?;

    // can't use cargo run since we can't pass -L args to it
    let path = format!("target/debug/{}", target);
    let mut run_cmd = process::Command::new(path);
    run_cmd.arg("-artifact_prefix=artifacts/")
           .arg("corpus") // must be last arg
           .env("ASAN_OPTIONS", "detect_odr_violation=0");
    exec_cmd(&mut run_cmd)?;
    Ok(())
}

#[cfg(unix)]
fn exec_cmd(cmd: &mut process::Command) -> ::std::io::Result<process::ExitStatus> {
    use std::os::unix::process::CommandExt;
    Err(cmd.exec())
}

#[cfg(not(unix))]
fn exec_cmd(cmd: &mut process::Command) -> ::std::io::Result<process::ExitStatus> {
    cmd.status()
}
<|endoftext|>


<commit_before>extern crate rustc_serialize;
extern crate docopt;
#[macro_use]
extern crate aws_abacus;

use docopt::Docopt;
use std::path;
use std::fs::File;
use std::io::BufReader;
use std::io::BufRead;
use aws_abacus::elb_log_files;

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

    let debug = args.flag_debug;

    let log_location = &path::Path::new(&args.arg_log_location);
    debug!(debug, "Running summary on {}.", log_location.to_str().unwrap());

    let mut filenames = Vec::new();
    match elb_log_files::file_list(log_location, &mut filenames) {
        Ok(_) => {
            debug!(debug, "Found {} files.", filenames.len());
            let mut record_count = 0;
            for filename in filenames {
                debug!(debug, "Processing file {}.", filename.path().display());
                match File::open(filename.path()) {
                    Ok(file) => {
                        let buffered_file = BufReader::new(&file);
                        // let lines = buffered_file.lines();
                        // for line in lines {
                        //     // let l = line.unwrap();
                        //     // println!("{}", l);
                        //
                        // }
                        let current_file_count = buffered_file.lines().count();
                        record_count += current_file_count;
                        debug!(debug, "Found {} records.", current_file_count);
                    },
                    Err(e) => {
                        println!("{}", e);
                    }
                }
            }
            debug!(debug, "Found {} records.", record_count);
        },
        Err(e) => println!("An error occurred."),
    };
}

const USAGE: &'static str = "
aws-abacus

Usage:
  aws-abacus <log-location>
  aws-abacus (-d | --debug) <log-location>
  aws-abacus (-h | --help)

Options:
  -h --help     Show this screen.
  -d --debug    Turn on debug output
";

#[derive(Debug, RustcDecodable)]
struct Args {
    arg_log_location: String,
    flag_debug: bool,
}
<commit_msg>Refactored the file handling out of main.<commit_after>extern crate rustc_serialize;
extern crate docopt;
#[macro_use]
extern crate aws_abacus;
extern crate walkdir;

use docopt::Docopt;
use std::path;
use std::fs::File;
use std::io::BufReader;
use std::io::BufRead;
use aws_abacus::elb_log_files;
use walkdir::DirEntry;

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

    let debug = args.flag_debug;

    let log_location = &path::Path::new(&args.arg_log_location);
    debug!(debug, "Running summary on {}.", log_location.to_str().unwrap());

    let mut filenames = Vec::new();
    match elb_log_files::file_list(log_location, &mut filenames) {
        Ok(_) => {
            debug!(debug, "Found {} files.", filenames.len());
            let record_count = handle_files(filenames);
            debug!(debug, "Found {} records.", record_count);
        },
        Err(e) => println!("An error occurred."),
    };
}

fn handle_files(filenames: Vec<walkdir::DirEntry>) -> usize {
    let mut record_count = 0;
    for filename in filenames {
        // debug!(debug, "Processing file {}.", filename.path().display());
        match File::open(filename.path()) {
            Ok(file) => {
                let buffered_file = BufReader::new(&file);
                // let lines = buffered_file.lines();
                // for line in lines {
                //     // let l = line.unwrap();
                //     // println!("{}", l);
                //
                // }
                let current_file_count = buffered_file.lines().count();
                record_count += current_file_count;
                // debug!(debug, "Found {} records.", current_file_count);
            },
            Err(e) => {
                println!("{}", e);
            }
        }
    }

    record_count
}

const USAGE: &'static str = "
aws-abacus

Usage:
  aws-abacus <log-location>
  aws-abacus (-d | --debug) <log-location>
  aws-abacus (-h | --help)

Options:
  -h --help     Show this screen.
  -d --debug    Turn on debug output
";

#[derive(Debug, RustcDecodable)]
struct Args {
    arg_log_location: String,
    flag_debug: bool,
}
<|endoftext|>


<commit_before>extern crate hsm;

fn main() {
}
<commit_msg>remove main.rs<commit_after><|endoftext|>


<commit_before>extern crate rand;

use std::collections::{HashMap, HashSet};

use rand::random;

// Documents
type DocId = u64;

// Index
struct InvertedIndex<'x> {
    // Token --> [ DocId ]
    index: HashMap<&'x str, Vec<DocId>>,
}

impl<'x> InvertedIndex<'x> {
    fn new() -> InvertedIndex<'x> {
        return InvertedIndex { index: HashMap::new() };
    }

    fn tokenize(&self, payload: &'x str) -> Vec<&'x str> {
        return payload.split_whitespace().collect();
    }

    fn index(&mut self, payload: &'x str) -> DocId {
        let id: DocId = random();
        let tokens = self.tokenize(payload);
        for token in tokens {
            self.index.entry(token).or_insert(vec![]).push(id);
        }
        id
    }

    fn search(&self, query: &str) -> HashSet<DocId> {
        let mut docs: HashSet<DocId> = HashSet::new();
        let tokens = self.tokenize(query);
        for token in tokens {
            match self.index.get(token) {
                Some(ids) => {
                    for id in ids {
                        docs.insert(*id);
                    }
                }
                None => {}
            }
        }
        docs
    }
}

fn main() {
    let mut idx = InvertedIndex::new();
    idx.index("The quick brown fox jumps over the lazy dog");
    idx.index("the world is flat");
    println!("{:?}", idx.search("the"));
    println!("{:?}", idx.search("foo"));
}
<commit_msg>lifetimes are hard…<commit_after>extern crate rand;

use std::collections::{HashMap, HashSet};

use rand::random;

// Documents
type DocId = u64;

// Index
struct InvertedIndex {
    // Token --> [ DocId ]
    index: HashMap<String, Vec<DocId>>,

    // DocId --> Body
    docs: HashMap<DocId, String>,
}

impl InvertedIndex {
    fn new() -> InvertedIndex {
        return InvertedIndex {
            index: HashMap::new(),
            docs: HashMap::new(),
        };
    }

    fn tokenize(&self, payload: &str) -> Vec<String> {
        let lower = payload.to_lowercase();
        let tokens: Vec<_> = lower.split_whitespace().collect();
        let mut ret = Vec::new();
        for token in tokens {
            ret.push(token.to_string());
        }
        ret
    }

    fn index(&mut self, payload: String) -> DocId {
        // Generate document id
        let id: DocId = random();

        // Tokenize document
        let tokens = self.tokenize(&payload);

        // Store whole document
        self.docs.insert(id, payload);

        // Index document by tokens
        for token in tokens {
            self.index
                .entry(token)
                .or_insert(vec![])
                .push(id);
        }
        id
    }

    fn search(&self, query: String) -> HashSet<DocId> {
        let mut docs = HashSet::new();
        let tokens = self.tokenize(&query);
        for token in &tokens {
            match self.index.get(token) {
                Some(ids) => {
                    for id in ids {
                        docs.insert(*id);
                    }
                }
                _ => {}
            }
        }
        docs
    }

    fn lookup(&self, doc_id: DocId) -> Option<&String> {
        self.docs.get(&doc_id)
        // match self.docs.get(&doc_id) {
        //     Some(doc) => println!("{}: {}", doc_id, doc),
        //     None => println!("None"),
        // }
    }
}

fn main() {
    // Create and populate documents
    let mut idx = InvertedIndex::new();
    idx.index("The quick brown fox jumps over the lazy dog".to_string());
    idx.index("life, universe, and everything".to_string());
    idx.index("The world is flat".to_string());

    // Search for a term
    let query = "what the";
    let doc_ids = idx.search(query.to_string());

    // Display found documents
    for doc_id in &doc_ids {
        let doc = idx.lookup(*doc_id);
        println!("Query({}) -> DocId({}) -> Document({:?})",
                 query,
                 doc_id,
                 doc);
    }
}
<|endoftext|>


<commit_before>extern crate sdl2;
extern crate assimp;
extern crate cgmath;

use assimp::Importer;
use sdl2::pixels::Color;
use sdl2::event::Event;
use sdl2::keyboard::Keycode;
use sdl2::rect::Point;
use sdl2::render::Renderer;
use std::cmp::Ordering;
use cgmath::InnerSpace;
use cgmath::Vector3;
use cgmath::Vector4;
use cgmath::Zero;
use cgmath::Matrix4;
use cgmath::SquareMatrix;

static WIDTH: u32 = 700;
static HEIGHT: u32 = 700;
static mut Z_BUFFER: [f32; 800 * 800] = [-1.; 800 * 800];

fn sort_points_by_y(points: &mut Vec<Vector3<f32>>) {
    for _ in 0..(points.len() - 1) {
        for j in 0..(points.len() - 1) {
            if points[j].y > points[j + 1].y {
                points.swap(j, j + 1);
            }
        }
    }
}

fn clamp<N>(a: N, min: N, max: N) -> N where N: PartialOrd {
    if a < min { return min }
    if a > max { return max }
    a
}

fn interpolate(min: f32, max: f32, gradient: f32) -> f32 {
    min + (max - min) * clamp(gradient, 0., 1.)
}

fn get_line_points(start: Point, end: Point) -> Vec<Point> {
    let mut x0 = start.x();
    let mut y0 = start.y();
    let mut x1 = end.x();
    let mut y1 = end.y();

    let steep = (y1 - y0).abs() > (x1 - x0).abs();

    if steep {
        std::mem::swap(&mut x0, &mut y0);
        std::mem::swap(&mut x1, &mut y1);
    }

    let reverse = x0 > x1;

    if reverse {
        std::mem::swap(&mut x0, &mut x1);
        std::mem::swap(&mut y0, &mut y1);
    }

    let dx = x1 - x0;
    let dy = (y1 - y0).abs();

    let mut err = dx / 2;
    let mut y = y0;
    let ystep = match y0.cmp(&y1) {
        Ordering::Less => 1,
        _ => -1
    };

    let mut points: Vec<Point> = vec![];

    for x in x0..x1 {
        if steep {
            points.push(Point::new(y, x));
        } else {
            points.push(Point::new(x, y));
        }

        err -= dy;

        if err < 0 {
            y += ystep;
            err += dx;
        }
    }

    points
}

trait TinyRenderer {
    fn pixel(&mut self, i32, i32, f32, Color);
    fn point(&mut self, Vector3<f32>, Color);
    fn line(&mut self, Point, Point, Color);
    fn process_scan_line(&mut self, i32, Vector3<f32>, Vector3<f32>, Vector3<f32>, Vector3<f32>, Color);
    fn triangle(&mut self, Vector3<f32>, Vector3<f32>, Vector3<f32>, Color);
}

impl<'a> TinyRenderer for Renderer<'a> {
    fn pixel(&mut self, x: i32, y: i32, z: f32, c: Color, ) {
        let index = (x + y * WIDTH as i32) as usize;

        if unsafe { Z_BUFFER[index] < z } {
            let current_color = self.draw_color();
            self.set_draw_color(c);

            self.draw_point(Point::new(x, y)).unwrap();

            unsafe {
                Z_BUFFER[index] = z;
            }

            self.set_draw_color(current_color);
        }
    }

    fn point(&mut self, p: Vector3<f32>, c: Color) {
        if p.x >= 0. && p.y >= 0. && p.x < WIDTH as f32 && p.y < HEIGHT as f32 {
            self.pixel(p.x as i32, p.y as i32, p.z, c);
        }
    }

    fn line(&mut self, start: Point, end: Point, c: Color) {
        let current_color = self.draw_color();
        self.set_draw_color(c);

        let points = get_line_points(start, end);

        for p in 0..points.len() {
            self.draw_point(points[p]).unwrap();
        }

        self.set_draw_color(current_color);
    }

    fn process_scan_line(&mut self, y: i32, pa: Vector3<f32>, pb: Vector3<f32>, pc: Vector3<f32>, pd: Vector3<f32>, c: Color) {
        let grad1 = match (pa.y as i32).cmp(&(pb.y as i32)) {
            Ordering::Equal => 1.,
            _ => (y as f32 - pa.y) / (pb.y - pa.y)
        };

        let grad2 = match (pc.y as i32).cmp(&(pd.y as i32)) {
            Ordering::Equal => 1.,
            _ => (y as f32 - pc.y) / (pd.y - pc.y)
        };

        let mut sx = interpolate(pa.x, pb.x, grad1) as i32;
        let mut ex = interpolate(pc.x, pd.x, grad2) as i32;

        if sx > ex {
            std::mem::swap(&mut sx, &mut ex);
        }

        let z1 = interpolate(pa.z, pb.z, grad1);
        let z2 = interpolate(pc.z, pd.z, grad2);

        for x in sx..ex {
            let gradient = (x - sx) as f32 / (ex - sx) as f32;

            let z = interpolate(z1, z2, gradient);
            self.point(Vector3::<f32>::new(x as f32, y as f32, z), c);
        }
    }

    fn triangle(&mut self, p0: Vector3<f32>, p1: Vector3<f32>, p2: Vector3<f32>, c: Color) {
        let mut points = vec![p0, p1, p2];
        sort_points_by_y(&mut points);

        let dp0p1 = match ((points[1].y - points[0].y) as i32).cmp(&0) {
            Ordering::Greater => (points[1].x - points[0].x) / (points[1].y - points[0].y),
            _ => 0.
        };

        let dp0p2 = match ((points[2].y - points[0].y) as i32).cmp(&0) {
            Ordering::Greater => (points[2].x - points[0].x) / (points[2].y - points[0].y),
            _ => 0.
        };

        for y in points[0].y as i32..points[2].y as i32 {
            if y < points[1].y as i32 {
                if dp0p1 > dp0p2 {
                    self.process_scan_line(y, points[0], points[2], points[0], points[1], c);
                } else {
                    self.process_scan_line(y, points[0], points[1], points[0], points[2], c);
                }
            } else {
                if dp0p1 > dp0p2 {
                    self.process_scan_line(y, points[0], points[2], points[1], points[2], c);
                } else {
                    self.process_scan_line(y, points[1], points[2], points[0], points[2], c);
                }
            }
        }
    }
}

fn main() {
    let importer = Importer::new();
    let scene = importer.read_file("resources/model.obj").unwrap();

    let sdl_context = sdl2::init().unwrap();
    let video_subsystem = sdl_context.video().unwrap();

    let window = video_subsystem.window("tinyrenderer-rs", WIDTH, HEIGHT)
        .position_centered()
        .opengl()
        .build()
        .unwrap();

    let mut renderer = window.renderer().build().unwrap();

    renderer.set_draw_color(Color::RGB(0, 0, 0));
    renderer.clear();

    let camera = Vector3::new(0., 0., 3.);
    let light_dir = Vector3::new(0., 0., -1.);
    let mut projection = Matrix4::<f32>::identity();
    let mut viewport = Matrix4::<f32>::identity();
    let (x, y, w, h) = (WIDTH as f32 / 8., HEIGHT as f32 / 8., WIDTH as f32 * 3. / 4., HEIGHT as f32 * 3. / 4.);
    viewport[3][0] = x + w / 2.;
    viewport[3][1] = y + h / 2.;
    viewport[3][2] = 255. / 2.; //depth

    viewport[0][0] = w / 2.;
    viewport[1][1] = h / 2.;
    viewport[2][2] = 255. / 2.;

    projection[2][3] = -1. / camera.z;

    for mesh in scene.mesh_iter() {
        for face in mesh.face_iter() {
            let mut screen_coords: [Vector3<f32>; 3] = [Vector3::zero(); 3];
            let mut world_coords: [Vector3<f32>; 3] = [Vector3::zero(); 3];

            for j in 0..3 {
                let v: Vector3<f32> = match mesh.get_vertex(face[j]) {
                    Some(x) => x.into(),
                    None => Vector3::<f32>::new(0., 0., 0.)
                };

                //let (p1, p2) = ((v.x + 1.) * WIDTH as f32 / 2., (v.y + 1.) * HEIGHT as f32 / 2.);
                // m2v(viewport * projection * v2m(v));
                let m = viewport * projection * Vector4::<f32>::new(v.x, v.y, v.z, 1.);
                let result_vector = Vector3::<f32>::new(m.x / m.w, HEIGHT as f32 - (m.y / m.w), m.z / m.w);

                screen_coords[j as usize] = result_vector;

                world_coords[j as usize] = v;
            }

            let n = (world_coords[2] - world_coords[0]).cross(world_coords[1] - world_coords[0]).normalize();
            let intensity = n.dot(light_dir);

            if intensity > 0.0 { // back-face culling
                renderer.triangle(
                    screen_coords[0],
                    screen_coords[1],
                    screen_coords[2],
                    Color::RGB(
                        (intensity * 255.) as u8,
                        (intensity * 255.) as u8,
                        (intensity * 255.) as u8
                    )
                );
            }
        }
    }

    renderer.present();

    let mut event_pump = sdl_context.event_pump().unwrap();

    'running: loop {
        for event in event_pump.poll_iter() {
            match event {
                Event::Quit {..} | Event::KeyDown { keycode: Some(Keycode::Escape), .. } => {
                    break 'running
                },
                _ => {}
            }
        }
        //code here
    }
}
<commit_msg>Added viewport fn<commit_after>extern crate sdl2;
extern crate assimp;
extern crate cgmath;

use assimp::Importer;
use sdl2::pixels::Color;
use sdl2::event::Event;
use sdl2::keyboard::Keycode;
use sdl2::rect::Point;
use sdl2::render::Renderer;
use std::cmp::Ordering;
use cgmath::InnerSpace;
use cgmath::Vector3;
use cgmath::Vector4;
use cgmath::Zero;
use cgmath::Matrix4;
use cgmath::SquareMatrix;

static WIDTH: u32 = 700;
static HEIGHT: u32 = 700;
static mut Z_BUFFER: [f32; 800 * 800] = [-1.; 800 * 800];

fn sort_points_by_y(points: &mut Vec<Vector3<f32>>) {
    for _ in 0..(points.len() - 1) {
        for j in 0..(points.len() - 1) {
            if points[j].y > points[j + 1].y {
                points.swap(j, j + 1);
            }
        }
    }
}

fn clamp<N>(a: N, min: N, max: N) -> N where N: PartialOrd {
    if a < min { return min }
    if a > max { return max }
    a
}

fn interpolate(min: f32, max: f32, gradient: f32) -> f32 {
    min + (max - min) * clamp(gradient, 0., 1.)
}

fn get_line_points(start: Point, end: Point) -> Vec<Point> {
    let mut x0 = start.x();
    let mut y0 = start.y();
    let mut x1 = end.x();
    let mut y1 = end.y();

    let steep = (y1 - y0).abs() > (x1 - x0).abs();

    if steep {
        std::mem::swap(&mut x0, &mut y0);
        std::mem::swap(&mut x1, &mut y1);
    }

    let reverse = x0 > x1;

    if reverse {
        std::mem::swap(&mut x0, &mut x1);
        std::mem::swap(&mut y0, &mut y1);
    }

    let dx = x1 - x0;
    let dy = (y1 - y0).abs();

    let mut err = dx / 2;
    let mut y = y0;
    let ystep = match y0.cmp(&y1) {
        Ordering::Less => 1,
        _ => -1
    };

    let mut points: Vec<Point> = vec![];

    for x in x0..x1 {
        if steep {
            points.push(Point::new(y, x));
        } else {
            points.push(Point::new(x, y));
        }

        err -= dy;

        if err < 0 {
            y += ystep;
            err += dx;
        }
    }

    points
}

trait TinyRenderer {
    fn pixel(&mut self, i32, i32, f32, Color);
    fn point(&mut self, Vector3<f32>, Color);
    fn line(&mut self, Point, Point, Color);
    fn process_scan_line(&mut self, i32, Vector3<f32>, Vector3<f32>, Vector3<f32>, Vector3<f32>, Color);
    fn triangle(&mut self, Vector3<f32>, Vector3<f32>, Vector3<f32>, Color);
}

impl<'a> TinyRenderer for Renderer<'a> {
    fn pixel(&mut self, x: i32, y: i32, z: f32, c: Color, ) {
        let index = (x + y * WIDTH as i32) as usize;

        if unsafe { Z_BUFFER[index] < z } {
            let current_color = self.draw_color();
            self.set_draw_color(c);

            self.draw_point(Point::new(x, y)).unwrap();

            unsafe {
                Z_BUFFER[index] = z;
            }

            self.set_draw_color(current_color);
        }
    }

    fn point(&mut self, p: Vector3<f32>, c: Color) {
        if p.x >= 0. && p.y >= 0. && p.x < WIDTH as f32 && p.y < HEIGHT as f32 {
            self.pixel(p.x as i32, p.y as i32, p.z, c);
        }
    }

    fn line(&mut self, start: Point, end: Point, c: Color) {
        let current_color = self.draw_color();
        self.set_draw_color(c);

        let points = get_line_points(start, end);

        for p in 0..points.len() {
            self.draw_point(points[p]).unwrap();
        }

        self.set_draw_color(current_color);
    }

    fn process_scan_line(&mut self, y: i32, pa: Vector3<f32>, pb: Vector3<f32>, pc: Vector3<f32>, pd: Vector3<f32>, c: Color) {
        let grad1 = match (pa.y as i32).cmp(&(pb.y as i32)) {
            Ordering::Equal => 1.,
            _ => (y as f32 - pa.y) / (pb.y - pa.y)
        };

        let grad2 = match (pc.y as i32).cmp(&(pd.y as i32)) {
            Ordering::Equal => 1.,
            _ => (y as f32 - pc.y) / (pd.y - pc.y)
        };

        let mut sx = interpolate(pa.x, pb.x, grad1) as i32;
        let mut ex = interpolate(pc.x, pd.x, grad2) as i32;

        if sx > ex {
            std::mem::swap(&mut sx, &mut ex);
        }

        let z1 = interpolate(pa.z, pb.z, grad1);
        let z2 = interpolate(pc.z, pd.z, grad2);

        for x in sx..ex {
            let gradient = (x - sx) as f32 / (ex - sx) as f32;

            let z = interpolate(z1, z2, gradient);
            self.point(Vector3::<f32>::new(x as f32, y as f32, z), c);
        }
    }

    fn triangle(&mut self, p0: Vector3<f32>, p1: Vector3<f32>, p2: Vector3<f32>, c: Color) {
        let mut points = vec![p0, p1, p2];
        sort_points_by_y(&mut points);

        let dp0p1 = match ((points[1].y - points[0].y) as i32).cmp(&0) {
            Ordering::Greater => (points[1].x - points[0].x) / (points[1].y - points[0].y),
            _ => 0.
        };

        let dp0p2 = match ((points[2].y - points[0].y) as i32).cmp(&0) {
            Ordering::Greater => (points[2].x - points[0].x) / (points[2].y - points[0].y),
            _ => 0.
        };

        for y in points[0].y as i32..points[2].y as i32 {
            if y < points[1].y as i32 {
                if dp0p1 > dp0p2 {
                    self.process_scan_line(y, points[0], points[2], points[0], points[1], c);
                } else {
                    self.process_scan_line(y, points[0], points[1], points[0], points[2], c);
                }
            } else {
                if dp0p1 > dp0p2 {
                    self.process_scan_line(y, points[0], points[2], points[1], points[2], c);
                } else {
                    self.process_scan_line(y, points[1], points[2], points[0], points[2], c);
                }
            }
        }
    }
}

fn viewport(x: f32, y: f32, w: f32, h: f32) -> Matrix4<f32> {
    let mut viewport = Matrix4::<f32>::identity();
    viewport[3][0] = x + w / 2.;
    viewport[3][1] = y + h / 2.;
    viewport[3][2] = 255. / 2.; //depth

    viewport[0][0] = w / 2.;
    viewport[1][1] = h / 2.;
    viewport[2][2] = 255. / 2.;
    return viewport;
}

// Matrix lookat(Vec3f eye, Vec3f center, Vec3f up) {
//     Vec3f z = (eye-center).normalize();
//     Vec3f x = (up^z).normalize();
//     Vec3f y = (z^x).normalize();
//     Matrix res = Matrix::identity(4);
//     for (int i=0; i<3; i++) {
//         res[0][i] = x[i];
//         res[1][i] = y[i];
//         res[2][i] = z[i];
//         res[i][3] = -center[i];
//     }
//     return res;
// }

fn main() {
    let importer = Importer::new();
    let scene = importer.read_file("resources/model.obj").unwrap();

    let sdl_context = sdl2::init().unwrap();
    let video_subsystem = sdl_context.video().unwrap();

    let window = video_subsystem.window("tinyrenderer-rs", WIDTH, HEIGHT)
        .position_centered()
        .opengl()
        .build()
        .unwrap();

    let mut renderer = window.renderer().build().unwrap();

    renderer.set_draw_color(Color::RGB(0, 0, 0));
    renderer.clear();

    let camera = Vector3::new(0., 0., 3.);
    let light_dir = Vector3::new(0., 0., -1.).normalize();
    let mut projection = Matrix4::<f32>::identity();
    let (x, y, w, h) = (WIDTH as f32 / 8., HEIGHT as f32 / 8., WIDTH as f32 * 3. / 4., HEIGHT as f32 * 3. / 4.);
    let viewport = viewport(x, y, w, h);

    projection[2][3] = -1. / camera.z;

    for mesh in scene.mesh_iter() {
        for face in mesh.face_iter() {
            let mut screen_coords: [Vector3<f32>; 3] = [Vector3::zero(); 3];
            let mut world_coords: [Vector3<f32>; 3] = [Vector3::zero(); 3];

            for j in 0..3 {
                let v: Vector3<f32> = match mesh.get_vertex(face[j]) {
                    Some(x) => x.into(),
                    None => Vector3::<f32>::new(0., 0., 0.)
                };

                //let (p1, p2) = ((v.x + 1.) * WIDTH as f32 / 2., (v.y + 1.) * HEIGHT as f32 / 2.);
                // m2v(ViewPort*Projection*ModelView*Matrix(v));
                let m = viewport * projection * Vector4::<f32>::new(v.x, v.y, v.z, 1.);
                let result_vector = Vector3::<f32>::new(m.x / m.w, HEIGHT as f32 - (m.y / m.w), m.z / m.w);

                screen_coords[j as usize] = result_vector;

                world_coords[j as usize] = v;
            }

            let n = (world_coords[2] - world_coords[0]).cross(world_coords[1] - world_coords[0]).normalize();
            let intensity = n.dot(light_dir);

            if intensity > 0.0 { // back-face culling
                renderer.triangle(
                    screen_coords[0],
                    screen_coords[1],
                    screen_coords[2],
                    Color::RGB(
                        (intensity * 255.) as u8,
                        (intensity * 255.) as u8,
                        (intensity * 255.) as u8
                    )
                );
            }
        }
    }

    renderer.present();

    let mut event_pump = sdl_context.event_pump().unwrap();

    'running: loop {
        for event in event_pump.poll_iter() {
            match event {
                Event::Quit {..} | Event::KeyDown { keycode: Some(Keycode::Escape), .. } => {
                    break 'running
                },
                _ => {}
            }
        }
        //code here
    }
}
<|endoftext|>


<commit_before>extern crate piston;
extern crate graphics;
extern crate glutin_window;
extern crate opengl_graphics;
extern crate noise;
extern crate num;
extern crate rustc_serialize;
extern crate time;

use std::path::Path;

use piston::window::WindowSettings;
use piston::event::{ Event, Events };
use piston::input::{ Button, Input, Key };

use glutin_window::GlutinWindow as Window;
use opengl_graphics::{OpenGL, GlGraphics, Texture};

use graphics::Image;
use graphics::rectangle::square;

// Why pub? Because that makes the docs work.
pub mod mapgen;
pub mod core;
pub mod model;
pub mod renderer;

use core::{Config};
use core::state;
use core::state::State;

use renderer::Renderer;

fn main() {
  let state = state::game_state::Game::new();

  let gl_context = OpenGL::_2_1;

  let config = Config::load().unwrap();

  let window_settings =
    WindowSettings::new(config.game_title().clone(),
                        config.window_size() ).exit_on_esc(true);
  let window = Window::new(gl_context, window_settings);

  // Create the image object and attach a square Rectangle object inside.
  let image = Image::new().rect(square(100.0, 10.0, 200.0));
  // A texture to use with the image
  let texture = Texture::from_path(Path::new("./assets/stamos.png")).unwrap();

  // This is the object used for drawing
  let mut gl = GlGraphics::new(gl_context);
  let mut renderer = Renderer::new();

  for event in window.events() {
    match event {
      Event::Input(Input::Press(Button::Keyboard(Key::Return))) =>
        println!("Return pressed!"),

      Event::Input(Input::Release(Button::Keyboard(Key::Return))) =>
        println!("Return released!"),

      Event::Render(args) => {
        use graphics::*;
        gl.draw(args.viewport(), |c, gl| {
          clear([1.0, 1.0, 1.0, 1.0], gl);

          state.render(&args, gl, &mut renderer);

          image.draw(&texture, default_draw_state(), c.transform, gl);
        });
      },

      _ => {}
    }
  }
}
<commit_msg>Fix some style inconsistencies<commit_after>extern crate piston;
extern crate graphics;
extern crate glutin_window;
extern crate opengl_graphics;
extern crate noise;
extern crate num;
extern crate rustc_serialize;
extern crate time;

use std::path::Path;

use piston::window::WindowSettings;
use piston::event::{Event, Events};
use piston::input::{Button, Input, Key};

use glutin_window::GlutinWindow as Window;
use opengl_graphics::{OpenGL, GlGraphics, Texture};

use graphics::Image;
use graphics::rectangle::square;

// Why pub? Because that makes the docs work.
pub mod mapgen;
pub mod core;
pub mod model;
pub mod renderer;

use core::Config;
use core::state;
use core::state::State;

use renderer::Renderer;

fn main() {
  let state = state::game_state::Game::new();

  let gl_context = OpenGL::_2_1;

  let config = Config::load().unwrap();

  let window_settings =
    WindowSettings::new(config.game_title().clone(),
                        config.window_size() ).exit_on_esc(true);
  let window = Window::new(gl_context, window_settings);

  // Create the image object and attach a square Rectangle object inside.
  let image = Image::new().rect(square(100.0, 10.0, 200.0));
  // A texture to use with the image
  let texture = Texture::from_path(Path::new("./assets/stamos.png")).unwrap();

  // This is the object used for drawing
  let mut gl = GlGraphics::new(gl_context);
  let mut renderer = Renderer::new();

  for event in window.events() {
    match event {
      Event::Input(Input::Press(Button::Keyboard(Key::Return))) =>
        println!("Return pressed!"),

      Event::Input(Input::Release(Button::Keyboard(Key::Return))) =>
        println!("Return released!"),

      Event::Render(args) => {
        use graphics::*;
        gl.draw(args.viewport(), |c, gl| {
          clear([1.0, 1.0, 1.0, 1.0], gl);

          state.render(&args, gl, &mut renderer);

          image.draw(&texture, default_draw_state(), c.transform, gl);
        });
      },

      _ => {}
    }
  }
}
<|endoftext|>


<commit_before>// Copyright 2015 Till Höppner
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//    http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#![feature(libc, plugin)]
#![plugin(regex_macros)]

extern crate ilc;
extern crate chrono;
extern crate docopt;
extern crate rustc_serialize;
extern crate libc;
extern crate regex;
#[macro_use]
extern crate log;
extern crate env_logger;

use std::fs::File;
use std::io::{ self, BufReader };
use std::str::FromStr;

use docopt::Docopt;

use chrono::offset::fixed::FixedOffset;
use chrono::naive::date::NaiveDate;

use ilc::context::Context;
use ilc::format::{ self, Encode, Decode };

static USAGE: &'static str = r#"
d8b   888
Y8P   888
      888
888   888    .d8888b
888   888   d88P"
888   888   888
888   888   Y88b.
888   888    "Y8888P

A converter and statistics utility for IRC log files.

Usage:
  ilc parse <file>...
  ilc convert <informat> <outformat> [--date DATE] [--tz SECS] [--channel CH]
  ilc (-h | --help | -v | --version)

Options:
  -h --help         Show this screen.
  -v --version      Show the version (duh).
  --date DATE       Override the date for this log. ISO 8601, YYYY-MM-DD.
  --tz SECONDS      UTC offset in the direction of the western hemisphere. [default: 0]
  --channel CH      Set a channel for the given log.
"#;

#[derive(RustcDecodable, Debug)]
struct Args {
    cmd_parse: bool,
    cmd_convert: bool,
    arg_file: Vec<String>,
    flag_help: bool,
    flag_version: bool,
    flag_date: Option<String>,
    flag_tz: i32,
    flag_channel: Option<String>
}

/*fn encode<'a, W, F>(format: &str) -> F where F: Encode<'a, W> {
    match format {
        "weechat3" => format::weechat3::Weechat3,
        "energymech" => format::energymech::Energymech
    }
}*/

fn main() {
    env_logger::init().unwrap();
    let args: Args = Docopt::new(USAGE)
               .and_then(|d| d.decode())
               .unwrap_or_else(|e| e.exit());
    if args.flag_help {
        println!("{}", USAGE);
        unsafe { libc::funcs::c95::stdlib::exit(1) }
    }

    let context = Context {
        timezone: FixedOffset::west(args.flag_tz),
        override_date: args.flag_date.and_then(|d| NaiveDate::from_str(&d).ok()),
        channel: args.flag_channel.clone()
    };

    if args.cmd_parse {
        let mut parser = format::energymech::Energymech;
        let formatter = format::binary::Binary;
        for file in args.arg_file {
            let f: BufReader<File> = BufReader::new(File::open(file).unwrap());
            let iter = parser.decode(&context, f);
            for e in iter {
                info!("Parsed: {:?}", e);
                drop(formatter.encode(&context, io::stdout(), &e.unwrap()));
            }
        }
    }

    if args.cmd_convert {
        let stdin = io::stdin();

        let mut parser = format::energymech::Energymech;
        let formatter = format::binary::Binary;

        for e in parser.decode(&context, stdin.lock()) {
            drop(formatter.encode(&context, io::stdout(), &e.unwrap()))
        }
    }
}
<commit_msg>Start CLI<commit_after>// Copyright 2015 Till Höppner
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//    http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#![feature(libc, plugin)]
#![plugin(regex_macros)]

extern crate ilc;
extern crate chrono;
extern crate docopt;
extern crate rustc_serialize;
extern crate libc;
extern crate regex;
#[macro_use]
extern crate log;
extern crate env_logger;

use std::fs::File;
use std::io::{ self, Read, BufRead, BufReader, Write };
use std::str::FromStr;

use docopt::Docopt;

use chrono::offset::fixed::FixedOffset;
use chrono::naive::date::NaiveDate;

use ilc::context::Context;
use ilc::event::Event;
use ilc::format::{ self, Encode, Decode };

static USAGE: &'static str = r#"
d8b   888
Y8P   888
      888
888   888    .d8888b
888   888   d88P"
888   888   888
888   888   Y88b.
888   888    "Y8888P

A converter and statistics utility for IRC log files.

Usage:
  ilc parse <file>...
  ilc convert <informat> <outformat> [--date DATE] [--tz SECS] [--channel CH]
  ilc (-h | --help | -v | --version)

Options:
  -h --help         Show this screen.
  -v --version      Show the version (duh).
  --date DATE       Override the date for this log. ISO 8601, YYYY-MM-DD.
  --tz SECONDS      UTC offset in the direction of the western hemisphere. [default: 0]
  --channel CH      Set a channel for the given log.
"#;

#[derive(RustcDecodable, Debug)]
struct Args {
    cmd_parse: bool,
    cmd_convert: bool,
    arg_file: Vec<String>,
    arg_informat: Option<String>,
    arg_outformat: Option<String>,
    flag_help: bool,
    flag_version: bool,
    flag_date: Option<String>,
    flag_tz: i32,
    flag_channel: Option<String>
}

/*fn encode<'a, W, F>(format: &str) -> F where F: Encode<'a, W> {
    match format {
        "weechat3" => format::weechat3::Weechat3,
        "energymech" => format::energymech::Energymech
    }
}*/

fn main() {
    env_logger::init().unwrap();
    let args: Args = Docopt::new(USAGE)
               .and_then(|d| d.decode())
               .unwrap_or_else(|e| e.exit());
    if args.flag_help {
        println!("{}", USAGE);
        unsafe { libc::funcs::c95::stdlib::exit(1) }
    }

    let context = Context {
        timezone: FixedOffset::west(args.flag_tz),
        override_date: args.flag_date.and_then(|d| NaiveDate::from_str(&d).ok()),
        channel: args.flag_channel.clone()
    };

    if args.cmd_parse {
        let mut parser = format::energymech::Energymech;
        let formatter = format::binary::Binary;
        for file in args.arg_file {
            let f: BufReader<File> = BufReader::new(File::open(file).unwrap());
            let iter = parser.decode(&context, f);
            for e in iter {
                info!("Parsed: {:?}", e);
                drop(formatter.encode(&context, io::stdout(), &e.unwrap()));
            }
        }
    }

    if args.cmd_convert {
        let stdin = io::stdin();

        let mut parser: &mut Decode<&mut BufRead, Box<Iterator<Item=Event>>> = match args.arg_informat.map(|s| s.as_ref()) {
            Some("energymech") => &mut format::energymech::Energymech,
            Some("weechat3") => &mut format::weechat3::Weechat3,
            Some("binary") => &mut format::binary::Binary
        };
        let formatter: &Encode<&mut Write> = match args.arg_outformat.map(|s| s.as_ref()) {
            Some("energymech") => &format::energymech::Energymech,
            Some("weechat3") => &format::weechat3::Weechat3,
            Some("binary") => &format::binary::Binary
        };

        for e in parser.decode(&context, &mut stdin.lock()) {
            drop(formatter.encode(&context, &mut io::stdout(), &e.unwrap()))
        }
    }
}
<|endoftext|>


<commit_before>extern crate chrono;
#[macro_use]
extern crate diesel;
#[macro_use]
extern crate diesel_codegen;
extern crate dotenv;

use std::env;

use diesel::{ Connection, LoadDsl, result, sqlite };
use dotenv::dotenv;

pub mod domain {
	use chrono::naive;

	#[derive(Queryable)]
	pub struct Book {
	    id : i32,
	    title : Option<String>,
	    date : Option<naive::NaiveDateTime>,
	}
}

pub mod schema {
    infer_schema!("dotenv:DATABASE_URL");
}

fn main() {
    use self::schema::books::dsl::*;
	let database_url = env::var("DATABASE_URL").unwrap();
	let conn = sqlite::SqliteConnection::establish(&database_url).unwrap();
    let res = books.load::<domain::Book>(&conn);
}
<commit_msg>struct Book declaration corrected.<commit_after>extern crate chrono;
#[macro_use]
extern crate diesel;
#[macro_use]
extern crate diesel_codegen;
extern crate dotenv;

use std::env;

use diesel::{ Connection, LoadDsl, result, sqlite };
use dotenv::dotenv;

pub mod domain {
	use chrono::naive;

	#[derive(Queryable)]
	pub struct Book {
	    id : i32,
	    title : Option<String>,
	    save_date : Option<naive::NaiveDateTime>,
	}
}

pub mod schema {
    infer_schema!("dotenv:DATABASE_URL");
}

fn main() {
    use self::schema::books::dsl::*;
	let database_url = env::var("DATABASE_URL").unwrap();
	let conn = sqlite::SqliteConnection::establish(&database_url).unwrap();
    let res = books.load::<domain::Book>(&conn);
}
<|endoftext|>


<commit_before>#[macro_use]
extern crate clap;

mod wiz { mod extraction; }

use clap::{App, Arg};

arg_enum! {
    #[derive(Debug)]
    enum Method {
        Install,
        Remove
    }
}

fn main() {
    let arg_matches = App::new("wiz")
        .version("0.1.0")

        .arg(Arg::with_name("method")
             .help("Specify what to do with the specified package")
             .index(1)
             .possible_values(&Method::variants())
             .required(true))

        .arg(Arg::with_name("package")
             .help("Specify package")
             .index(2)
             .required(true))

        .get_matches();

    let method = value_t!(arg_matches.value_of("method"), Method).unwrap();
    let package = arg_matches.value_of("package").unwrap_or("invalid");

    match method {
        Method::Install => println!("install: {}", package),
        Method::Remove => println!("remove: {}", package)
    }
}
<commit_msg>Not mod-ing files individually now<commit_after>#[macro_use]
extern crate clap;

mod wiz;

use clap::{App, Arg};

arg_enum! {
    #[derive(Debug)]
    enum Method {
        Install,
        Remove
    }
}

fn main() {
    let arg_matches = App::new("wiz")
        .version("0.1.0")

        .arg(Arg::with_name("method")
             .help("Specify what to do with the specified package")
             .index(1)
             .possible_values(&Method::variants())
             .required(true))

        .arg(Arg::with_name("package")
             .help("Specify package")
             .index(2)
             .required(true))

        .get_matches();

    let method = value_t!(arg_matches.value_of("method"), Method).unwrap();
    let package = arg_matches.value_of("package").unwrap_or("invalid");

    match method {
        Method::Install => println!("install: {}", package),
        Method::Remove => println!("remove: {}", package)
    }
}
<|endoftext|>


<commit_before>// Copyright 2020 Google LLC
//
// Use of this source code is governed by an MIT-style license that can be found
// in the LICENSE file or at https://opensource.org/licenses/MIT.

//! Unix-specific utilities for working with the filesystem.

use std::ffi::OsString;
use std::path::Path;

/// An extended attribute of a file.
///
/// On Linux, extended attributes can be obtained using `getfattr` and set with
/// `setfattr` utilities. On macOS, they can be manipulated through the `xattr`
/// utility.
///
/// See the [Wikipedia] article for more details.
///
/// [Wikipedia]: https://en.wikipedia.org/wiki/Extended_file_attributes
#[derive(Debug)]
pub struct ExtAttr {
    /// A name of the extended attribute.
    pub name: OsString,
    /// A value of the extended attribute.
    pub value: Vec<u8>,
}

/// Returns an iterator over extended attributes of the specified file.
///
/// # Errors
///
/// The function will fail if a list of extended attributes of the file cannot
/// be obtained (e.g. when the file doesn't exist). Each iterator element is a
/// result itself and errors are possible e.g. when the attribute has been dele-
/// ted since we first listed it.
///
/// # Examples
///
/// ```no_run
/// use std::path::Path;
///
/// for attr in rrg::fs::unix::ext_attrs(Path::new("/tmp/foo")).unwrap() {
///     let attr = attr.unwrap();
///     let name = attr.name.to_string_lossy();
///     let value = String::from_utf8_lossy(&attr.value);
///     println!("{}: {}", name, value);
/// }
/// ```
pub fn ext_attrs<'p>(path: &'p std::path::Path) -> std::io::Result<ExtAttrs<'p>> {
    let names = ext_attr_names(path)?;

    Ok(ExtAttrs {
        path: path.as_ref(),
        names: names.into_iter(),
    })
}

/// Iterator over extended attributes of a file.
///
/// The iterator can be constructed with the [`ext_attrs`] function.
///
/// [`ext_attrs`]: fn.ext_attrs.html
pub struct ExtAttrs<'p> {
    path: &'p Path,
    names: std::vec::IntoIter<std::ffi::OsString>,
}

impl<'p> Iterator for ExtAttrs<'p> {

    type Item = std::io::Result<ExtAttr>;

    fn next(&mut self) -> Option<std::io::Result<ExtAttr>> {
        let name = self.names.next()?;
        let value = match ext_attr_value(self.path, &name) {
            Ok(value) => value,
            Err(error) => return Some(Err(error)),
        };

        Some(Ok(ExtAttr { name, value }))
    }
}

pub fn ext_attr_names<P>(path: P) -> std::io::Result<Vec<std::ffi::OsString>>
where
    P: AsRef<Path>,
{
    #[cfg(target_os = "linux")]
    use super::linux::ext_attr_names;

    #[cfg(target_os = "macos")]
    use super::macos::ext_attr_names;

    ext_attr_names(path)
}

pub fn ext_attr_value<P, S>(path: P, name: S) -> std::io::Result<Vec<u8>>
where
    P: AsRef<Path>,
    S: AsRef<std::ffi::OsStr>,
{
    #[cfg(target_os = "linux")]
    use super::linux::ext_attr_value;

    #[cfg(target_os = "macos")]
    use super::macos::ext_attr_value;

    ext_attr_value(path, name)
}

#[cfg(test)]
mod tests {

    use super::*;

    #[test]
    fn ext_attrs_non_existing() {
        let tempdir = tempfile::tempdir().unwrap();

        assert!(ext_attrs(&tempdir.path().join("foo")).is_err());
    }

    #[cfg(all(target_os = "linux", feature = "test-setfattr"))]
    #[test]
    fn ext_attrs_with_multiple_values() {
        let tempfile = tempfile::NamedTempFile::new().unwrap();
        setfattr(tempfile.path(), "user.abc", b"quux");
        setfattr(tempfile.path(), "user.def", b"norf");

        let mut results = ext_attrs(&tempfile.path()).unwrap()
            .map(Result::unwrap)
            .collect::<Vec<_>>();
        results.sort_by_key(|attr| attr.name.clone());

        assert_eq!(results.len(), 2);

        assert_eq!(results[0].name, "user.abc");
        assert_eq!(results[0].value, b"quux");

        assert_eq!(results[1].name, "user.def");
        assert_eq!(results[1].value, b"norf");
    }

    #[cfg(all(target_os = "linux", feature = "test-setfattr"))]
    #[test]
    fn ext_attrs_with_empty_value() {
        let tempfile = tempfile::NamedTempFile::new().unwrap();
        setfattr(tempfile.path(), "user.abc", b"");

        let results = ext_attrs(&tempfile.path()).unwrap()
            .map(Result::unwrap)
            .collect::<Vec<_>>();

        assert_eq!(results.len(), 1);

        assert_eq!(results[0].name, "user.abc");
        assert_eq!(results[0].value, b"");
    }

    #[cfg(all(target_os = "linux", feature = "test-setfattr"))]
    #[test]
    fn ext_attrs_with_bytes_value() {
        let tempfile = tempfile::NamedTempFile::new().unwrap();
        setfattr(tempfile.path(), "user.abc", b"\xff\xfe\xff\xfe\xff");

        let results = ext_attrs(&tempfile.path()).unwrap()
            .map(Result::unwrap)
            .collect::<Vec<_>>();

        assert_eq!(results.len(), 1);

        assert_eq!(results[0].name, "user.abc");
        assert_eq!(results[0].value, b"\xff\xfe\xff\xfe\xff");
    }

    #[cfg(all(target_os = "linux", feature = "test-setfattr"))]
    fn setfattr<P, S>(path: P, name: S, value: &[u8])
    where
        P: AsRef<std::path::Path>,
        S: AsRef<std::ffi::OsStr>,
    {
        use std::os::unix::ffi::OsStrExt as _;

        assert! {
            std::process::Command::new("setfattr")
                .arg("--name").arg(name)
                .arg("--value").arg(std::ffi::OsStr::from_bytes(value))
                .arg(path.as_ref().as_os_str())
                .status()
                .unwrap()
                .success()
        };
    }

    // TODO: Add macOS tests.
    // TODO: Document and add tests for collecting attributes of a symlink.
}

// TODO: Move this into the `rrg-proto` crate once generic purpose utilities are
// moved to a separate crate.
impl Into<rrg_proto::jobs::StatEntry_ExtAttr> for ExtAttr {

    fn into(self) -> rrg_proto::jobs::StatEntry_ExtAttr {
        use std::os::unix::ffi::OsStringExt as _;

        let mut proto = rrg_proto::jobs::StatEntry_ExtAttr::new();
        proto.set_name(self.name.into_vec());
        proto.set_value(self.value);

        proto
    }
}
<commit_msg>Add macOS tests for the xattr iterator.<commit_after>// Copyright 2020 Google LLC
//
// Use of this source code is governed by an MIT-style license that can be found
// in the LICENSE file or at https://opensource.org/licenses/MIT.

//! Unix-specific utilities for working with the filesystem.

use std::ffi::OsString;
use std::path::Path;

/// An extended attribute of a file.
///
/// On Linux, extended attributes can be obtained using `getfattr` and set with
/// `setfattr` utilities. On macOS, they can be manipulated through the `xattr`
/// utility.
///
/// See the [Wikipedia] article for more details.
///
/// [Wikipedia]: https://en.wikipedia.org/wiki/Extended_file_attributes
#[derive(Debug)]
pub struct ExtAttr {
    /// A name of the extended attribute.
    pub name: OsString,
    /// A value of the extended attribute.
    pub value: Vec<u8>,
}

/// Returns an iterator over extended attributes of the specified file.
///
/// # Errors
///
/// The function will fail if a list of extended attributes of the file cannot
/// be obtained (e.g. when the file doesn't exist). Each iterator element is a
/// result itself and errors are possible e.g. when the attribute has been dele-
/// ted since we first listed it.
///
/// # Examples
///
/// ```no_run
/// use std::path::Path;
///
/// for attr in rrg::fs::unix::ext_attrs(Path::new("/tmp/foo")).unwrap() {
///     let attr = attr.unwrap();
///     let name = attr.name.to_string_lossy();
///     let value = String::from_utf8_lossy(&attr.value);
///     println!("{}: {}", name, value);
/// }
/// ```
pub fn ext_attrs<'p>(path: &'p std::path::Path) -> std::io::Result<ExtAttrs<'p>> {
    let names = ext_attr_names(path)?;

    Ok(ExtAttrs {
        path: path.as_ref(),
        names: names.into_iter(),
    })
}

/// Iterator over extended attributes of a file.
///
/// The iterator can be constructed with the [`ext_attrs`] function.
///
/// [`ext_attrs`]: fn.ext_attrs.html
pub struct ExtAttrs<'p> {
    path: &'p Path,
    names: std::vec::IntoIter<std::ffi::OsString>,
}

impl<'p> Iterator for ExtAttrs<'p> {

    type Item = std::io::Result<ExtAttr>;

    fn next(&mut self) -> Option<std::io::Result<ExtAttr>> {
        let name = self.names.next()?;
        let value = match ext_attr_value(self.path, &name) {
            Ok(value) => value,
            Err(error) => return Some(Err(error)),
        };

        Some(Ok(ExtAttr { name, value }))
    }
}

pub fn ext_attr_names<P>(path: P) -> std::io::Result<Vec<std::ffi::OsString>>
where
    P: AsRef<Path>,
{
    #[cfg(target_os = "linux")]
    use super::linux::ext_attr_names;

    #[cfg(target_os = "macos")]
    use super::macos::ext_attr_names;

    ext_attr_names(path)
}

pub fn ext_attr_value<P, S>(path: P, name: S) -> std::io::Result<Vec<u8>>
where
    P: AsRef<Path>,
    S: AsRef<std::ffi::OsStr>,
{
    #[cfg(target_os = "linux")]
    use super::linux::ext_attr_value;

    #[cfg(target_os = "macos")]
    use super::macos::ext_attr_value;

    ext_attr_value(path, name)
}

#[cfg(test)]
mod tests {

    use super::*;

    #[test]
    fn ext_attrs_non_existing() {
        let tempdir = tempfile::tempdir().unwrap();

        assert!(ext_attrs(&tempdir.path().join("foo")).is_err());
    }

    #[cfg(all(target_os = "linux", feature = "test-setfattr"))]
    #[test]
    fn ext_attrs_with_multiple_values() {
        let tempfile = tempfile::NamedTempFile::new().unwrap();
        setfattr(tempfile.path(), "user.abc", b"quux");
        setfattr(tempfile.path(), "user.def", b"norf");

        let mut results = ext_attrs(&tempfile.path()).unwrap()
            .map(Result::unwrap)
            .collect::<Vec<_>>();
        results.sort_by_key(|attr| attr.name.clone());

        assert_eq!(results.len(), 2);

        assert_eq!(results[0].name, "user.abc");
        assert_eq!(results[0].value, b"quux");

        assert_eq!(results[1].name, "user.def");
        assert_eq!(results[1].value, b"norf");
    }

    #[cfg(target_os = "macos")]
    #[test]
    fn ext_attrs_with_multiple_values() {
        let tempfile = tempfile::NamedTempFile::new().unwrap();
        xattr(tempfile.path(), "user.abc", b"quux");
        xattr(tempfile.path(), "user.def", b"norf");

        let mut results = ext_attrs(&tempfile.path()).unwrap()
            .map(Result::unwrap)
            .collect::<Vec<_>>();
        results.sort_by_key(|attr| attr.name.clone());

        assert_eq!(results.len(), 2);

        assert_eq!(results[0].name, "user.abc");
        assert_eq!(results[0].value, b"quux");

        assert_eq!(results[1].name, "user.def");
        assert_eq!(results[1].value, b"norf");
    }

    #[cfg(all(target_os = "linux", feature = "test-setfattr"))]
    #[test]
    fn ext_attrs_with_empty_value() {
        let tempfile = tempfile::NamedTempFile::new().unwrap();
        setfattr(tempfile.path(), "user.abc", b"");

        let results = ext_attrs(&tempfile.path()).unwrap()
            .map(Result::unwrap)
            .collect::<Vec<_>>();

        assert_eq!(results.len(), 1);

        assert_eq!(results[0].name, "user.abc");
        assert_eq!(results[0].value, b"");
    }

    #[cfg(target_os = "macos")]
    #[test]
    fn ext_attrs_with_empty_value() {
        let tempfile = tempfile::NamedTempFile::new().unwrap();
        xattr(tempfile.path(), "user.abc", b"");

        let results = ext_attrs(&tempfile.path()).unwrap()
            .map(Result::unwrap)
            .collect::<Vec<_>>();

        assert_eq!(results.len(), 1);

        assert_eq!(results[0].name, "user.abc");
        assert_eq!(results[0].value, b"");
    }

    #[cfg(all(target_os = "linux", feature = "test-setfattr"))]
    #[test]
    fn ext_attrs_with_bytes_value() {
        let tempfile = tempfile::NamedTempFile::new().unwrap();
        setfattr(tempfile.path(), "user.abc", b"\xff\xfe\xff\xfe\xff");

        let results = ext_attrs(&tempfile.path()).unwrap()
            .map(Result::unwrap)
            .collect::<Vec<_>>();

        assert_eq!(results.len(), 1);

        assert_eq!(results[0].name, "user.abc");
        assert_eq!(results[0].value, b"\xff\xfe\xff\xfe\xff");
    }

    #[cfg(target_os = "macos")]
    #[test]
    fn ext_attrs_with_bytes_value() {
        let tempfile = tempfile::NamedTempFile::new().unwrap();
        xattr(tempfile.path(), "user.abc", b"\xff\xfe\xff\xfe\xff");

        let results = ext_attrs(&tempfile.path()).unwrap()
            .map(Result::unwrap)
            .collect::<Vec<_>>();

        assert_eq!(results.len(), 1);

        assert_eq!(results[0].name, "user.abc");
        assert_eq!(results[0].value, b"\xff\xfe\xff\xfe\xff");
    }

    #[cfg(all(target_os = "linux", feature = "test-setfattr"))]
    fn setfattr<P, S>(path: P, name: S, value: &[u8])
    where
        P: AsRef<std::path::Path>,
        S: AsRef<std::ffi::OsStr>,
    {
        use std::os::unix::ffi::OsStrExt as _;

        assert! {
            std::process::Command::new("setfattr")
                .arg("--name").arg(name)
                .arg("--value").arg(std::ffi::OsStr::from_bytes(value))
                .arg(path.as_ref().as_os_str())
                .status()
                .unwrap()
                .success()
        };
    }

    #[cfg(target_os = "macos")]
    fn xattr<P, S>(path: P, name: S, value: &[u8])
    where
        P: AsRef<std::path::Path>,
        S: AsRef<std::ffi::OsStr>,
    {
        use std::os::unix::ffi::OsStrExt as _;

        assert! {
            std::process::Command::new("xattr")
                .arg(name)
                .arg(std::ffi::OsStr::from_bytes(value))
                .arg(path.as_ref().as_os_str())
                .status()
                .unwrap()
                .success()
        };
    }

    // TODO: Document and add tests for collecting attributes of a symlink.
}

// TODO: Move this into the `rrg-proto` crate once generic purpose utilities are
// moved to a separate crate.
impl Into<rrg_proto::jobs::StatEntry_ExtAttr> for ExtAttr {

    fn into(self) -> rrg_proto::jobs::StatEntry_ExtAttr {
        use std::os::unix::ffi::OsStringExt as _;

        let mut proto = rrg_proto::jobs::StatEntry_ExtAttr::new();
        proto.set_name(self.name.into_vec());
        proto.set_value(self.value);

        proto
    }
}
<|endoftext|>


<commit_before>/*!
Migrant can be used as a library so you can embed the management of migrations
into your binary and don't need to use a secondary tool in production environments.

The majority of `src/main.rs` could be copied, or just select functionality.
*/
extern crate migrant;

use std::env;
use std::path::PathBuf;
use migrant::Config;

pub fn main() {
    let dir = env::current_dir().unwrap();
    let config_path = match migrant::search_for_config(&dir) {
        None => {
            migrant::Config::init(&dir).expect("failed to initialize project");
            return;
        }
        Some(p) => p,
    };
    let base_dir = config_path.parent()
        .map(PathBuf::from)
        .expect("failed to get parent dir");
    let config = Config::load(&config_path)
        .expect("failed to load config");

    // This will fail if no migration files are present!
    // Run all available `up` migrations
    // migrant::Migrator::with_config(&config, &config_path, &base_dir)
    //     .direction(migrant::Direction::Up)
    //     .all(true)
    //     .apply()
    //     .expect("failed to apply migrations")

    migrant::list(&config, &base_dir)
        .expect("failed to list migrations");
}
<commit_msg>update embedded example<commit_after>/*!
Migrant can be used as a library so you can embed the management of migrations
into your binary and don't need to use a secondary tool in production environments.

The majority of `src/main.rs` could be copied, or just select functionality.
*/
extern crate migrant;

use std::env;
use std::path::PathBuf;
use migrant::Config;

pub fn main() {
    let dir = env::current_dir().unwrap();
    let config_path = match migrant::search_for_config(&dir) {
        None => {
            migrant::Config::init(&dir).expect("failed to initialize project");
            return;
        }
        Some(p) => p,
    };
    let base_dir = config_path.parent()
        .map(PathBuf::from)
        .expect("failed to get parent dir");
    let config = Config::load(&config_path)
        .expect("failed to load config");

    // This will fail if no migration files are present!
    // Run all available `up` migrations
    // migrant::Migrator::with_config(&config, &config_path)
    //     .direction(migrant::Direction::Up)
    //     .all(true)
    //     .apply()
    //     .expect("failed to apply migrations")

    migrant::list(&config, &base_dir)
        .expect("failed to list migrations");
}
<|endoftext|>