<commit_before>//! Executable toolkit for working with sdf files.

extern crate docopt;
extern crate env_logger;
extern crate rustc_serialize;
extern crate sdf;

use std::process::exit;
use std::u32;

use docopt::Docopt;

use sdf::error::Error;

const USAGE: &'static str = "
Read and process .sdf files.

Usage:
    sdf block <infile> <index> \
                             <block>
    sdf convert <infile> <outfile>
    sdf info <infile> \
                             [--brief]
    sdf record <infile> <index>
    sdf (-h | --help)
    \
                             sdf --version

Options:
    -h --help   Show this screen.
    \
                             --version   Show sdf-rs and sdfifc library versions.
    --brief     \
                             Only provide file information from the header, do not inspect the \
                             file itself.
";

#[derive(Debug, RustcDecodable)]
struct Args {
    flag_brief: bool,
    flag_version: bool,
    arg_block: usize,
    arg_index: u32,
    arg_infile: String,
    arg_outfile: String,
    cmd_block: bool,
    cmd_convert: bool,
    cmd_info: bool,
    cmd_record: bool,
}

fn error_exit(message: &str, err: Error) -> ! {
    println!("ERROR: {}: {}", message, err);
    exit(1);
}

#[cfg_attr(test, allow(dead_code))]
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_version {
        let library_version = sdf::library_version().unwrap_or_else(|e| {
            error_exit("Unable to get library version", e)
        });
        println!("      sdf-rs version: {}", env!("CARGO_PKG_VERSION"));
        println!("  sdfifc api version: {}.{}",
                 library_version.api_major,
                 library_version.api_minor);
        println!("sdfifc build version: {}", library_version.build_version);
        println!("    sdfifc build tag: {}", library_version.build_tag);
        exit(0);
    }

    if args.cmd_convert {
        sdf::File::convert(args.arg_infile, args.arg_outfile)
            .unwrap_or_else(|e| error_exit("Problem when converting file", e));
        exit(0);
    }

    let mut file = sdf::File::open(args.arg_infile.clone())
                       .unwrap_or_else(|e| error_exit("Unable to open file", e));
    if !args.flag_brief {
        file.reindex().unwrap_or_else(|e| error_exit("Unable to reindex file", e));
    }

    if args.cmd_info {
        let info = file.info().unwrap_or_else(|e| error_exit("Unable to retrieve file info", e));
        println!("      instrument: {}", info.instrument);
        println!("          serial: {}", info.serial);
        println!("           epoch: {}", info.epoch);
        println!("  group velocity: {}", info.v_group);
        println!("   sampling time: {}", info.sampling_time);
        println!("gps synchronized: {}", info.gps_synchronized);
        println!("number of facets: {}", info.num_facets);
        if args.flag_brief {
            exit(0);
        }

        let record = file.read().unwrap_or_else(|e| error_exit("Unable to read first point", e));
        let start_time = record.time_external;
        println!("      start time: {}", start_time);
        file.seek(u32::MAX).unwrap_or_else(|e| error_exit("Unable to seek to end of file", e));
        let record = file.read().unwrap_or_else(|e| error_exit("Unable to read last point", e));
        let end_time = record.time_external;
        println!("        end time: {}", end_time);
        let npoints = file.tell()
                          .unwrap_or_else(|e| error_exit("Unable to get index of next record", e));
        println!("number of points: {}", npoints);

        exit(0);
    }

    if args.cmd_record {
        file.seek(args.arg_index)
            .unwrap_or_else(|e| {
                error_exit(&format!("Unable to seek to index {}", args.arg_index)[..],
                           e)
            });
        let record = file.read().unwrap_or_else(|e| error_exit("Unable to read point", e));
        println!("{}", record);
        exit(0);
    }

    if args.cmd_block {
        file.seek(args.arg_index)
            .unwrap_or_else(|e| {
                error_exit(&format!("Unable to seek to index {}", args.arg_index)[..],
                           e)
            });
        let record = file.read().unwrap_or_else(|e| error_exit("Unable to read point", e));
        if args.arg_block < record.blocks.len() {
            println!("{}", record.blocks[args.arg_block]);
            exit(0);
        } else {
            println!("ERROR: record only has {} blocks", record.blocks.len());
            exit(1);
        }
    }

    unreachable!()
}
<commit_msg>Print block information with record command<commit_after>//! Executable toolkit for working with sdf files.

extern crate docopt;
extern crate env_logger;
extern crate rustc_serialize;
extern crate sdf;

use std::process::exit;
use std::u32;

use docopt::Docopt;

use sdf::error::Error;

const USAGE: &'static str = "
Read and process .sdf files.

Usage:
    sdf convert <infile> <outfile>
    sdf info <infile> \
                             [--brief]
    sdf record <infile> <index>
    sdf (-h | --help)
    \
                             sdf --version

Options:
    -h --help   Show this screen.
    \
                             --version   Show sdf-rs and sdfifc library versions.
    --brief     \
                             Only provide file information from the header, do not inspect the \
                             file itself.
";

#[derive(Debug, RustcDecodable)]
struct Args {
    flag_brief: bool,
    flag_version: bool,
    arg_index: u32,
    arg_infile: String,
    arg_outfile: String,
    cmd_convert: bool,
    cmd_info: bool,
    cmd_record: bool,
}

fn error_exit(message: &str, err: Error) -> ! {
    println!("ERROR: {}: {}", message, err);
    exit(1);
}

#[cfg_attr(test, allow(dead_code))]
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_version {
        let library_version = sdf::library_version().unwrap_or_else(|e| {
            error_exit("Unable to get library version", e)
        });
        println!("      sdf-rs version: {}", env!("CARGO_PKG_VERSION"));
        println!("  sdfifc api version: {}.{}",
                 library_version.api_major,
                 library_version.api_minor);
        println!("sdfifc build version: {}", library_version.build_version);
        println!("    sdfifc build tag: {}", library_version.build_tag);
        exit(0);
    }

    if args.cmd_convert {
        sdf::File::convert(args.arg_infile, args.arg_outfile)
            .unwrap_or_else(|e| error_exit("Problem when converting file", e));
        exit(0);
    }

    let mut file = sdf::File::open(args.arg_infile.clone())
                       .unwrap_or_else(|e| error_exit("Unable to open file", e));
    if !args.flag_brief {
        file.reindex().unwrap_or_else(|e| error_exit("Unable to reindex file", e));
    }

    if args.cmd_info {
        let info = file.info().unwrap_or_else(|e| error_exit("Unable to retrieve file info", e));
        println!("      instrument: {}", info.instrument);
        println!("          serial: {}", info.serial);
        println!("           epoch: {}", info.epoch);
        println!("  group velocity: {}", info.v_group);
        println!("   sampling time: {}", info.sampling_time);
        println!("gps synchronized: {}", info.gps_synchronized);
        println!("number of facets: {}", info.num_facets);
        if args.flag_brief {
            exit(0);
        }

        let record = file.read().unwrap_or_else(|e| error_exit("Unable to read first record", e));
        let start_time = record.time_external;
        println!("      start time: {}", start_time);
        file.seek(u32::MAX).unwrap_or_else(|e| error_exit("Unable to seek to end of file", e));
        let record = file.read().unwrap_or_else(|e| error_exit("Unable to read last record", e));
        let end_time = record.time_external;
        println!("        end time: {}", end_time);
        let records = file.tell()
                          .unwrap_or_else(|e| error_exit("Unable to get index of next record", e));
        println!("number of records: {}", records);

        exit(0);
    }

    if args.cmd_record {
        file.seek(args.arg_index)
            .unwrap_or_else(|e| {
                error_exit(&format!("Unable to seek to index {}", args.arg_index)[..],
                           e)
            });
        let record = file.read().unwrap_or_else(|e| error_exit("Unable to read record", e));
        println!("{}", record);
        for (i, block) in record.blocks.iter().enumerate() {
            println!("\nBlock {}", i);
            println!("{}", block);
        }
        exit(0);
    }

    unreachable!()
}
<|endoftext|>


<commit_before>#![cfg_attr(test, deny(warnings))]

extern crate atty;
extern crate chrono;
#[macro_use]
extern crate clap;
extern crate colored;
extern crate doug;
extern crate serde;
extern crate serde_json;

use std::io::stdout;

use atty::Stream;
use clap::{App, AppSettings, Arg, Shell, SubCommand};
use colored::Colorize;

use doug::*;
use std::process;

fn main() {
    if !atty::is(Stream::Stdout) {
        colored::control::set_override(false);
    }

    let mut cli =
        App::new("Doug")
            .version(crate_version!())
            .about("A time tracking command-line utility")
            .author(crate_authors!())
            .settings(&[
                AppSettings::DeriveDisplayOrder,
                AppSettings::GlobalVersion,
                AppSettings::SubcommandRequiredElseHelp,
                AppSettings::VersionlessSubcommands,
                AppSettings::DisableHelpSubcommand,
                AppSettings::ColorAuto,
            ]).arg(
                Arg::with_name("path")
                    .short("p")
                    .long("path")
                    .help("Path to load settings file from. (default: ~/.doug/settings.json)"),
            ).subcommand(
                SubCommand::with_name("start")
                    .about("Track new or existing project")
                    .arg(Arg::with_name("project").help(
                        "project to track. If missing, start subcommand behaves like restart.",
                    )),
            ).subcommand(
                SubCommand::with_name("status")
                    .about("Display elapsed time, start time, and running project name")
                    .arg(
                        Arg::with_name("t")
                            .short("t")
                            .long("time")
                            .help("Print time for currently tracked project."),
                    ).arg(Arg::with_name("s").short("s").long("simple").help(
                        "Print running project name or nothing if there isn't a running project.",
                    )),
            ).subcommand(SubCommand::with_name("stop").about("Stop any running projects"))
            .subcommand(SubCommand::with_name("s").about("Stop any running projects").settings(&[AppSettings::Hidden, AppSettings::HidePossibleValuesInHelp]))
            .subcommand(
                SubCommand::with_name("cancel")
                    .about("Stop running project and remove most recent time interval"),
            ).subcommand(SubCommand::with_name("restart").about("Track last running project"))
            .subcommand(SubCommand::with_name("r").about("Track last running project").settings(&[AppSettings::Hidden, AppSettings::HidePossibleValuesInHelp]))
            .subcommand(
                SubCommand::with_name("log").about("Display time intervals across all projects"),
            ).subcommand(
                SubCommand::with_name("report")
                    .about("Display aggregate time from projects")
                    .arg(
                        Arg::with_name("year")
                            .short("y")
                            .long("year")
                            .help("Limit report to past year. Use multiple to increase interval.")
                            .overrides_with_all(&["month", "week", "day", "from", "to"])
                            .multiple(true),
                    ).arg(
                        Arg::with_name("month")
                            .short("m")
                            .long("month")
                            .help("Limit report to past month. Use multiple to increase interval.")
                            .overrides_with_all(&["year", "week", "day", "from", "to"])
                            .multiple(true),
                    ).arg(
                        Arg::with_name("week")
                            .short("w")
                            .long("week")
                            .help("Limit report to past week. Use multiple to increase interval.")
                            .overrides_with_all(&["year", "month", "day", "from", "to"])
                            .multiple(true),
                    ).arg(
                        Arg::with_name("day")
                            .short("d")
                            .long("day")
                            .help("Limit report to past day. Use multiple to increase interval.")
                            .overrides_with_all(&["year", "month", "week", "from", "to"])
                            .multiple(true),
                    ).arg(
                        Arg::with_name("from")
                            .short("f")
                            .long("from")
                            .help("Date when report should start (e.g. 2018-1-1)")
                            .overrides_with_all(&["year", "month", "week", "day"])
                            .takes_value(true),
                    ).arg(
                        Arg::with_name("to")
                            .short("t")
                            .long("to")
                            .help("Date when report should end (e.g. 2018-1-20)")
                            .overrides_with_all(&["year", "month", "week", "day"])
                            .takes_value(true),
                    ),
            ).subcommand(
                SubCommand::with_name("amend")
                    .about("Change name of currently running project")
                    .arg(
                        Arg::with_name("project")
                            .help("new project name")
                            .required(true),
                    ),
            ).subcommand(
                SubCommand::with_name("edit")
                    .about("Edit last frame or currently running frame")
                    .arg(
                        Arg::with_name("start")
                            .short("s")
                            .long("start")
                            .help("starting date")
                            .takes_value(true),
                    ).arg(
                        Arg::with_name("end")
                            .short("e")
                            .long("end")
                            .help("ending date")
                            .takes_value(true),
                    ),
            )
            .subcommand(
                SubCommand::with_name("settings")
                .about("configure doug settings")
                .arg(
                    Arg::with_name("path")
                    .short("p")
                    .long("path")
                    .takes_value(true)
                    .help("path to store data file")
                    .long_help("path to store data file. this only affects the data file location. settings are stored in $HOME.")
                ).arg(
                    Arg::with_name("clear")
                    .short("c")
                    .long("clear")
                    .help("clear settings file")
                )
            ).subcommand(
                SubCommand::with_name("generate-completions")
                    .about("Generate completions")
                    .arg(
                        Arg::with_name("shell")
                            .help("shell to generate completion for (default: bash).")
                            .short("s")
                            .long("shell")
                            .possible_values(&["bash", "zsh", "fish", "powershell"])
                            .case_insensitive(true)
                            .default_value("bash")
                            .takes_value(true),
                    ),
            ).subcommand(
                SubCommand::with_name("delete")
                    .about("Delete all intervals for project")
                    .arg(
                        Arg::with_name("project")
                            .help("new project name")
                            .required(true),
                    ),
            );

    let matches = cli.clone().get_matches();

    let mut doug = match Doug::new(matches.value_of("path")) {
        Ok(x) => x,
        Err(e) => {
            eprintln!("Error: {}", e);
            process::exit(1)
        }
    };

    let results = match matches.subcommand() {
        ("start", Some(matches)) | ("s", Some(matches)) => match matches.value_of("project") {
            Some(project) => doug.start(project),
            // Restart last project if not argument is provided
            None => doug.restart(),
        },
        ("amend", Some(matches)) => match matches.value_of("project") {
            Some(project) => doug.amend(project),
            None => Err("Missing project name".to_string()),
        },
        ("delete", Some(matches)) => match matches.value_of("project") {
            Some(project) => doug.delete(project),
            None => Err("missing project name".to_string()),
        },
        ("status", Some(matches)) => doug.status(matches.is_present("s"), matches.is_present("t")),
        ("report", Some(matches)) => doug.report(
            matches.occurrences_of("year") as i32,
            matches.occurrences_of("month") as i32,
            matches.occurrences_of("week") as i32,
            matches.occurrences_of("day") as i32,
            matches.value_of("from"),
            matches.value_of("to"),
        ),
        ("generate-completions", Some(matches)) => match matches.value_of("shell") {
            Some("bash") => {
                cli.gen_completions_to("doug", Shell::Bash, &mut stdout());
                Ok(None)
            }
            Some("zsh") => {
                cli.gen_completions_to("doug", Shell::Zsh, &mut stdout());
                Ok(None)
            }
            Some("fish") => {
                cli.gen_completions_to("doug", Shell::Fish, &mut stdout());
                Ok(None)
            }
            Some("powershell") => {
                cli.gen_completions_to("doug", Shell::PowerShell, &mut stdout());
                Ok(None)
            }
            _ => Err("Invalid option".to_string()),
        },
        ("edit", Some(matches)) => doug.edit(matches.value_of("start"), matches.value_of("end")),
        ("stop", Some(_)) => doug.stop(),
        ("cancel", Some(_)) => doug.cancel(),
        ("restart", Some(_)) | ("r", Some(_)) => doug.restart(),
        ("log", Some(_)) => doug.log(),
        ("settings", Some(matches)) => {
            doug.settings(matches.value_of("path"), matches.is_present("clear"))
        }
        (_, Some(_)) | (_, None) => unreachable!(),
    };

    match results {
        Ok(m) => if let Some(m) = m {
            print!("{}", m)
        },
        Err(e) => {
            eprintln!("{} {}", "Error:".red(), e);
            process::exit(1)
        }
    }
}
<commit_msg>fix missing new line (#21)<commit_after>#![cfg_attr(test, deny(warnings))]

extern crate atty;
extern crate chrono;
#[macro_use]
extern crate clap;
extern crate colored;
extern crate doug;
extern crate serde;
extern crate serde_json;

use std::io::stdout;

use atty::Stream;
use clap::{App, AppSettings, Arg, Shell, SubCommand};
use colored::Colorize;

use doug::*;
use std::process;

fn main() {
    if !atty::is(Stream::Stdout) {
        colored::control::set_override(false);
    }

    let mut cli =
        App::new("Doug")
            .version(crate_version!())
            .about("A time tracking command-line utility")
            .author(crate_authors!())
            .settings(&[
                AppSettings::DeriveDisplayOrder,
                AppSettings::GlobalVersion,
                AppSettings::SubcommandRequiredElseHelp,
                AppSettings::VersionlessSubcommands,
                AppSettings::DisableHelpSubcommand,
                AppSettings::ColorAuto,
            ]).arg(
                Arg::with_name("path")
                    .short("p")
                    .long("path")
                    .help("Path to load settings file from. (default: ~/.doug/settings.json)"),
            ).subcommand(
                SubCommand::with_name("start")
                    .about("Track new or existing project")
                    .arg(Arg::with_name("project").help(
                        "project to track. If missing, start subcommand behaves like restart.",
                    )),
            ).subcommand(
                SubCommand::with_name("status")
                    .about("Display elapsed time, start time, and running project name")
                    .arg(
                        Arg::with_name("t")
                            .short("t")
                            .long("time")
                            .help("Print time for currently tracked project."),
                    ).arg(Arg::with_name("s").short("s").long("simple").help(
                        "Print running project name or nothing if there isn't a running project.",
                    )),
            ).subcommand(SubCommand::with_name("stop").about("Stop any running projects"))
            .subcommand(SubCommand::with_name("s").about("Stop any running projects").settings(&[AppSettings::Hidden, AppSettings::HidePossibleValuesInHelp]))
            .subcommand(
                SubCommand::with_name("cancel")
                    .about("Stop running project and remove most recent time interval"),
            ).subcommand(SubCommand::with_name("restart").about("Track last running project"))
            .subcommand(SubCommand::with_name("r").about("Track last running project").settings(&[AppSettings::Hidden, AppSettings::HidePossibleValuesInHelp]))
            .subcommand(
                SubCommand::with_name("log").about("Display time intervals across all projects"),
            ).subcommand(
                SubCommand::with_name("report")
                    .about("Display aggregate time from projects")
                    .arg(
                        Arg::with_name("year")
                            .short("y")
                            .long("year")
                            .help("Limit report to past year. Use multiple to increase interval.")
                            .overrides_with_all(&["month", "week", "day", "from", "to"])
                            .multiple(true),
                    ).arg(
                        Arg::with_name("month")
                            .short("m")
                            .long("month")
                            .help("Limit report to past month. Use multiple to increase interval.")
                            .overrides_with_all(&["year", "week", "day", "from", "to"])
                            .multiple(true),
                    ).arg(
                        Arg::with_name("week")
                            .short("w")
                            .long("week")
                            .help("Limit report to past week. Use multiple to increase interval.")
                            .overrides_with_all(&["year", "month", "day", "from", "to"])
                            .multiple(true),
                    ).arg(
                        Arg::with_name("day")
                            .short("d")
                            .long("day")
                            .help("Limit report to past day. Use multiple to increase interval.")
                            .overrides_with_all(&["year", "month", "week", "from", "to"])
                            .multiple(true),
                    ).arg(
                        Arg::with_name("from")
                            .short("f")
                            .long("from")
                            .help("Date when report should start (e.g. 2018-1-1)")
                            .overrides_with_all(&["year", "month", "week", "day"])
                            .takes_value(true),
                    ).arg(
                        Arg::with_name("to")
                            .short("t")
                            .long("to")
                            .help("Date when report should end (e.g. 2018-1-20)")
                            .overrides_with_all(&["year", "month", "week", "day"])
                            .takes_value(true),
                    ),
            ).subcommand(
                SubCommand::with_name("amend")
                    .about("Change name of currently running project")
                    .arg(
                        Arg::with_name("project")
                            .help("new project name")
                            .required(true),
                    ),
            ).subcommand(
                SubCommand::with_name("edit")
                    .about("Edit last frame or currently running frame")
                    .arg(
                        Arg::with_name("start")
                            .short("s")
                            .long("start")
                            .help("starting date")
                            .takes_value(true),
                    ).arg(
                        Arg::with_name("end")
                            .short("e")
                            .long("end")
                            .help("ending date")
                            .takes_value(true),
                    ),
            )
            .subcommand(
                SubCommand::with_name("settings")
                .about("configure doug settings")
                .arg(
                    Arg::with_name("path")
                    .short("p")
                    .long("path")
                    .takes_value(true)
                    .help("path to store data file")
                    .long_help("path to store data file. this only affects the data file location. settings are stored in $HOME.")
                ).arg(
                    Arg::with_name("clear")
                    .short("c")
                    .long("clear")
                    .help("clear settings file")
                )
            ).subcommand(
                SubCommand::with_name("generate-completions")
                    .about("Generate completions")
                    .arg(
                        Arg::with_name("shell")
                            .help("shell to generate completion for (default: bash).")
                            .short("s")
                            .long("shell")
                            .possible_values(&["bash", "zsh", "fish", "powershell"])
                            .case_insensitive(true)
                            .default_value("bash")
                            .takes_value(true),
                    ),
            ).subcommand(
                SubCommand::with_name("delete")
                    .about("Delete all intervals for project")
                    .arg(
                        Arg::with_name("project")
                            .help("new project name")
                            .required(true),
                    ),
            );

    let matches = cli.clone().get_matches();

    let mut doug = match Doug::new(matches.value_of("path")) {
        Ok(x) => x,
        Err(e) => {
            eprintln!("Error: {}", e);
            process::exit(1)
        }
    };

    let results = match matches.subcommand() {
        ("start", Some(matches)) | ("s", Some(matches)) => match matches.value_of("project") {
            Some(project) => doug.start(project),
            // Restart last project if not argument is provided
            None => doug.restart(),
        },
        ("amend", Some(matches)) => match matches.value_of("project") {
            Some(project) => doug.amend(project),
            None => Err("Missing project name".to_string()),
        },
        ("delete", Some(matches)) => match matches.value_of("project") {
            Some(project) => doug.delete(project),
            None => Err("missing project name".to_string()),
        },
        ("status", Some(matches)) => doug.status(matches.is_present("s"), matches.is_present("t")),
        ("report", Some(matches)) => doug.report(
            matches.occurrences_of("year") as i32,
            matches.occurrences_of("month") as i32,
            matches.occurrences_of("week") as i32,
            matches.occurrences_of("day") as i32,
            matches.value_of("from"),
            matches.value_of("to"),
        ),
        ("generate-completions", Some(matches)) => match matches.value_of("shell") {
            Some("bash") => {
                cli.gen_completions_to("doug", Shell::Bash, &mut stdout());
                Ok(None)
            }
            Some("zsh") => {
                cli.gen_completions_to("doug", Shell::Zsh, &mut stdout());
                Ok(None)
            }
            Some("fish") => {
                cli.gen_completions_to("doug", Shell::Fish, &mut stdout());
                Ok(None)
            }
            Some("powershell") => {
                cli.gen_completions_to("doug", Shell::PowerShell, &mut stdout());
                Ok(None)
            }
            _ => Err("Invalid option".to_string()),
        },
        ("edit", Some(matches)) => doug.edit(matches.value_of("start"), matches.value_of("end")),
        ("stop", Some(_)) => doug.stop(),
        ("cancel", Some(_)) => doug.cancel(),
        ("restart", Some(_)) | ("r", Some(_)) => doug.restart(),
        ("log", Some(_)) => doug.log(),
        ("settings", Some(matches)) => {
            doug.settings(matches.value_of("path"), matches.is_present("clear"))
        }
        (_, Some(_)) | (_, None) => unreachable!(),
    };

    match results {
        Ok(m) => if let Some(m) = m {
            println!("{}", m)
        },
        Err(e) => {
            eprintln!("{} {}", "Error:".red(), e);
            process::exit(1)
        }
    }
}
<|endoftext|>


<commit_before>extern crate sdl2;
extern crate vecmath;
extern crate rayon;

mod vec3d;
mod light;
mod scene;
mod material;
mod color;
mod shape;
mod sphere;
mod plane;

use scene::Scene;

use sdl2::pixels::PixelFormatEnum;
use sdl2::rect::Rect;
use sdl2::EventPump;
use sdl2::event::Event;
use sdl2::keyboard::Keycode;
use std::time::Instant;

use rayon::prelude::*;

// Return true for quit
fn handle_events(scene: &mut Scene,
                 resolution: u32,
                 event_pump: &mut EventPump,
                 x: i32,
                 y: i32)
                 -> bool {
    for event in event_pump.poll_iter() {
        match event {
            Event::Quit { .. } |
            Event::KeyDown { keycode: Some(Keycode::Escape), .. } => return true,
            Event::KeyDown { keycode: Some(Keycode::W), .. } => {
                scene.mv_camera_fwd();
            }
            Event::KeyDown { keycode: Some(Keycode::S), .. } => {
                scene.mv_camera_back();
            }
            _ => {}
        }
    }

    // TODO: Y rotation is incorrect
    let x_dist = ((resolution as i32) / 2) - x;
    let y_dist = ((resolution as i32) / 2) - y;
    let x_rot = x_dist as f64 * (-0.001);
    let y_rot = y_dist as f64 * (-0.001);
    scene.rot_camera(x_rot, y_rot);
    false
}

// Test scene
fn test_scene() -> Scene {
    use light::Light;
    use vec3d::Vec3d;
    use sphere::Sphere;
    use plane::Plane;

    let camera_pos: Vec3d = [0.0, 0.0, -100.0];

    let camera_dir: Vec3d = [0.0, 0.0, 1.0];
    let camera_up: Vec3d = [0.0, 1.0, 0.0];
    let light_pos: Vec3d = [50.0, 5.0, -100.0];

    let light = Light::new(light_pos, color::Color(0.6, 0.6, 0.6));
    let mut scene = Scene::new(light, camera_pos, camera_dir, camera_up);
    scene.add_shape(Box::new(Sphere::new([-20.0, -15.0, 45.0], 5.0, color::Color(1.0, 0.5, 0.5))));
    scene.add_shape(Box::new(Sphere::new([15.0, -10.0, 35.0], 5.0, color::Color(0.4, 0.4, 0.4))));
    scene.add_shape(Box::new(Sphere::new([0.0, -10.0, 25.0], 5.0, color::Color(0.5, 0.5, 1.0))));
    scene.add_shape(Box::new(Sphere::new([0.0, -120.0, 55.0], 100.0, color::WHITE)));
    scene.add_shape(Box::new(Sphere::new([0.0, 120.0, 55.0], 100.0, color::Color(1.0, 1.0, 0.0))));
    scene.add_shape(Box::new(Sphere::new([0.0, 0.0, 200.0], 100.0, color::Color(1.0, 0.5, 1.0))));
    scene.add_shape(Box::new(Sphere::from_material([15.0, 0.0, 40.0], 5.0, material::MIRROR)));
    scene.add_shape(Box::new(Sphere::new([-45.0, 0.0, 45.0], 20.0, color::Color(0.1, 0.1, 0.1))));

    scene.add_shape(Box::new(Plane::new([0.0, -200.0, 0.0], [0.0, 1.0, 0.0], color::Color(0.4, 0.4, 0.4))));
    scene.add_shape(Box::new(Plane::new([0.0, 200.0, 0.0], [0.0, -1.0, 0.0], color::Color(0.4, 0.4, 0.4))));
    scene.add_shape(Box::new(Plane::from_material([200.0, 0.0, 0.0], [-1.0, 0.0, 0.0], material::MIRROR)));
    scene.add_shape(Box::new(Plane::new([-200.0, 0.0, 0.0], [1.0, 0.0, 0.0], color::Color(0.8, 0.4, 0.8))));
    scene.add_shape(Box::new(Plane::new([0.0, 0.0, 200.0], [0.0, 0.0, -1.0], color::Color(0.4, 0.4, 0.4))));
    scene.add_shape(Box::new(Plane::new([0.0, 0.0, -200.0], [0.0, 0.0, 1.0], color::Color(0.4, 0.4, 0.4))));
    scene
}

// A simple test code that uses SDL for rendering
fn main() {
    let resolution: u32 = 512;
    let res_u = resolution as usize;
    let mut scene = test_scene();

    // Stuff from sdl2-rust example
    let sdl_context = sdl2::init().unwrap();
    let video_subsystem = sdl_context.video().unwrap();

    let window = video_subsystem.window("Ray", resolution, resolution)
        .position_centered()
        .opengl()
        .build()
        .unwrap();

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

    let mut texture =
        renderer.create_texture_streaming(PixelFormatEnum::RGB24, resolution, resolution)
            .unwrap();

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

    let mut lines: Vec<(usize, Vec<(u8, u8, u8)>)> = Vec::new();
    for line_no in 0..res_u {
        lines.push((line_no, Vec::with_capacity(res_u)));
    }

    let mut frame_cnt = 0;
    let mut time_stamp = Instant::now();
    loop {
        let (_, x, y) = sdl_context.mouse().mouse_state();
        let quit = handle_events(&mut scene, resolution, &mut event_pump, x, y);
        if quit {
            break;
        }

        if frame_cnt == 10 {
            let elapsed = time_stamp.elapsed();
            let msecs = (elapsed.as_secs() * 1000) as u64 + (elapsed.subsec_nanos() as u64 / 1000000);
            time_stamp = Instant::now();
            println!("FPS {}", (frame_cnt as f32) / (msecs as f32 / 1000.0));
            frame_cnt = 0;
        }

        scene.step();

        lines.par_iter_mut().for_each(|tup| {
            let (line_no, ref mut vec) = *tup;
            vec.drain(..);
            scene.line_iter_u8(res_u, res_u, line_no).fold((), |(), x| vec.push(x));
        });

        texture.with_lock(None, |buffer: &mut [u8], pitch: usize| {
                for tup in lines.iter() {
                    let (line_no, ref vec) = *tup;
                    let line_start = line_no * pitch;
                    let line_end = line_start + res_u * 3;
                    let line_buf = &mut buffer[line_start..line_end];
                    for (c, offset) in vec.iter().zip((0..).map(|x| 3 * x)) {
                        line_buf[offset + 0] = c.0;
                        line_buf[offset + 1] = c.1;
                        line_buf[offset + 2] = c.2;
                    }
                }
            }).unwrap();
        renderer.clear();
        renderer.copy(&texture,
                  None,
                  Some(Rect::new(0, 0, resolution, resolution)))
            .unwrap();
        renderer.present();
        frame_cnt += 1;
    }
}
<commit_msg>Don't use opengl context for no reason.<commit_after>extern crate sdl2;
extern crate vecmath;
extern crate rayon;

mod vec3d;
mod light;
mod scene;
mod material;
mod color;
mod shape;
mod sphere;
mod plane;

use scene::Scene;

use sdl2::pixels::PixelFormatEnum;
use sdl2::rect::Rect;
use sdl2::EventPump;
use sdl2::event::Event;
use sdl2::keyboard::Keycode;
use std::time::Instant;

use rayon::prelude::*;

// Return true for quit
fn handle_events(scene: &mut Scene,
                 resolution: u32,
                 event_pump: &mut EventPump,
                 x: i32,
                 y: i32)
                 -> bool {
    for event in event_pump.poll_iter() {
        match event {
            Event::Quit { .. } |
            Event::KeyDown { keycode: Some(Keycode::Escape), .. } => return true,
            Event::KeyDown { keycode: Some(Keycode::W), .. } => {
                scene.mv_camera_fwd();
            }
            Event::KeyDown { keycode: Some(Keycode::S), .. } => {
                scene.mv_camera_back();
            }
            _ => {}
        }
    }

    // TODO: Y rotation is incorrect
    let x_dist = ((resolution as i32) / 2) - x;
    let y_dist = ((resolution as i32) / 2) - y;
    let x_rot = x_dist as f64 * (-0.001);
    let y_rot = y_dist as f64 * (-0.001);
    scene.rot_camera(x_rot, y_rot);
    false
}

// Test scene
fn test_scene() -> Scene {
    use light::Light;
    use vec3d::Vec3d;
    use sphere::Sphere;
    use plane::Plane;

    let camera_pos: Vec3d = [0.0, 0.0, -100.0];

    let camera_dir: Vec3d = [0.0, 0.0, 1.0];
    let camera_up: Vec3d = [0.0, 1.0, 0.0];
    let light_pos: Vec3d = [50.0, 5.0, -100.0];

    let light = Light::new(light_pos, color::Color(0.6, 0.6, 0.6));
    let mut scene = Scene::new(light, camera_pos, camera_dir, camera_up);
    scene.add_shape(Box::new(Sphere::new([-20.0, -15.0, 45.0], 5.0, color::Color(1.0, 0.5, 0.5))));
    scene.add_shape(Box::new(Sphere::new([15.0, -10.0, 35.0], 5.0, color::Color(0.4, 0.4, 0.4))));
    scene.add_shape(Box::new(Sphere::new([0.0, -10.0, 25.0], 5.0, color::Color(0.5, 0.5, 1.0))));
    scene.add_shape(Box::new(Sphere::new([0.0, -120.0, 55.0], 100.0, color::WHITE)));
    scene.add_shape(Box::new(Sphere::new([0.0, 120.0, 55.0], 100.0, color::Color(1.0, 1.0, 0.0))));
    scene.add_shape(Box::new(Sphere::new([0.0, 0.0, 200.0], 100.0, color::Color(1.0, 0.5, 1.0))));
    scene.add_shape(Box::new(Sphere::from_material([15.0, 0.0, 40.0], 5.0, material::MIRROR)));
    scene.add_shape(Box::new(Sphere::new([-45.0, 0.0, 45.0], 20.0, color::Color(0.1, 0.1, 0.1))));

    scene.add_shape(Box::new(Plane::new([0.0, -200.0, 0.0], [0.0, 1.0, 0.0], color::Color(0.4, 0.4, 0.4))));
    scene.add_shape(Box::new(Plane::new([0.0, 200.0, 0.0], [0.0, -1.0, 0.0], color::Color(0.4, 0.4, 0.4))));
    scene.add_shape(Box::new(Plane::from_material([200.0, 0.0, 0.0], [-1.0, 0.0, 0.0], material::MIRROR)));
    scene.add_shape(Box::new(Plane::new([-200.0, 0.0, 0.0], [1.0, 0.0, 0.0], color::Color(0.8, 0.4, 0.8))));
    scene.add_shape(Box::new(Plane::new([0.0, 0.0, 200.0], [0.0, 0.0, -1.0], color::Color(0.4, 0.4, 0.4))));
    scene.add_shape(Box::new(Plane::new([0.0, 0.0, -200.0], [0.0, 0.0, 1.0], color::Color(0.4, 0.4, 0.4))));
    scene
}

// A simple test code that uses SDL for rendering
fn main() {
    let resolution: u32 = 512;
    let res_u = resolution as usize;
    let mut scene = test_scene();

    // Stuff from sdl2-rust example
    let sdl_context = sdl2::init().unwrap();
    let video_subsystem = sdl_context.video().unwrap();

    let window = video_subsystem.window("Ray", resolution, resolution)
        .position_centered()
        .build()
        .unwrap();

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

    let mut texture =
        renderer.create_texture_streaming(PixelFormatEnum::RGB24, resolution, resolution)
            .unwrap();

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

    let mut lines: Vec<(usize, Vec<(u8, u8, u8)>)> = Vec::new();
    for line_no in 0..res_u {
        lines.push((line_no, Vec::with_capacity(res_u)));
    }

    let mut frame_cnt = 0;
    let mut time_stamp = Instant::now();
    loop {
        let (_, x, y) = sdl_context.mouse().mouse_state();
        let quit = handle_events(&mut scene, resolution, &mut event_pump, x, y);
        if quit {
            break;
        }

        if frame_cnt == 10 {
            let elapsed = time_stamp.elapsed();
            let msecs = (elapsed.as_secs() * 1000) as u64 + (elapsed.subsec_nanos() as u64 / 1000000);
            time_stamp = Instant::now();
            println!("FPS {}", (frame_cnt as f32) / (msecs as f32 / 1000.0));
            frame_cnt = 0;
        }

        scene.step();

        lines.par_iter_mut().for_each(|tup| {
            let (line_no, ref mut vec) = *tup;
            vec.drain(..);
            scene.line_iter_u8(res_u, res_u, line_no).fold((), |(), x| vec.push(x));
        });

        texture.with_lock(None, |buffer: &mut [u8], pitch: usize| {
                for tup in lines.iter() {
                    let (line_no, ref vec) = *tup;
                    let line_start = line_no * pitch;
                    let line_end = line_start + res_u * 3;
                    let line_buf = &mut buffer[line_start..line_end];
                    for (c, offset) in vec.iter().zip((0..).map(|x| 3 * x)) {
                        line_buf[offset + 0] = c.0;
                        line_buf[offset + 1] = c.1;
                        line_buf[offset + 2] = c.2;
                    }
                }
            }).unwrap();
        renderer.clear();
        renderer.copy(&texture,
                  None,
                  Some(Rect::new(0, 0, resolution, resolution)))
            .unwrap();
        renderer.present();
        frame_cnt += 1;
    }
}
<|endoftext|>


<commit_before>use std::io::{Write, BufWriter};
use std::fs::File;
mod vector;
use vector::{Vec3, dot, cross, unit_vector};
mod ray;
use ray::Ray;

fn hit_sphere(center: Vec3, radius: f64, ray: Ray) -> bool {
  let oc = ray.origin() - center;
  let a: f64 = dot(ray.direction(), ray.direction());
  let b: f64 = dot(oc, ray.direction()) * 2.0;
  let c: f64 = dot(oc, oc) - radius * radius;
  let discriminant = b * b - 4.0 * a * c;
  return discriminant > 0.0
}

fn color(ray : Ray) -> Vec3 {
  if hit_sphere(Vec3::new(0.0, 0.0, -1.0), 0.5, ray) {
    return Vec3::new(1.0, 0.0, 0.0);
  }
  let unit_direction = ray.direction().unit_vector();
  let t = 0.5 * (unit_direction.y() + 1.0);
  return Vec3::new(1.0,1.0,1.0) * (1.0 - t) + Vec3::new(0.5,0.7,1.0) * t;
}

fn main() {
  let nx = 200;
  let ny = 100;
  let data = format!("{}\n{} {}\n{}\n", "P3", nx, ny, 255);
  let f = File::create("target/image.ppm").expect("Unable to create file");
  let mut f = BufWriter::new(f);
  f.write_all(data.as_bytes()).expect("Unable to write data");

  let lower_left_corner = Vec3::new(-2.0, -1.0, -1.0);
  let horizontal = Vec3::new(4.0, 0.0, 0.0);
  let vertical = Vec3::new(0.0, 2.0, 0.0);
  let origin = Vec3::new(0.0, 0.0, 0.0);

  for j in (0..ny).rev() {
    for i in 0..nx {
      let u = i as f64 / nx as f64;
      let v = j as f64 / ny as f64;
      let r = Ray::new(origin, lower_left_corner + horizontal * u + vertical * v);
      let col = color(r);

      let ir = (255.99*col.r()) as i32;
      let ig = (255.99*col.g()) as i32;
      let ib = (255.99*col.b()) as i32;
      f.write_all(format!("{} {} {}\n", ir, ig, ib).as_bytes()).expect("Unable to write data");
    }
  }
}<commit_msg>Calculate sphere color using surface normals<commit_after>use std::io::{Write, BufWriter};
use std::fs::File;
mod vector;
use vector::{Vec3, dot, cross, unit_vector};
mod ray;
use ray::Ray;

fn hit_sphere(center: Vec3, radius: f64, ray: Ray) -> f64 {
  let oc = ray.origin() - center;
  let a: f64 = dot(ray.direction(), ray.direction());
  let b: f64 = dot(oc, ray.direction()) * 2.0;
  let c: f64 = dot(oc, oc) - radius * radius;
  let discriminant = b * b - 4.0 * a * c;
  if discriminant < 0.0 {
    return -1.0
  }
  else {
    return (-b - discriminant.sqrt()) / (2.0 * a);
  }
}

fn color(ray : Ray) -> Vec3 {
  let t = hit_sphere(Vec3::new(0.0, 0.0, -1.0), 0.5, ray);
  if t > 0.0 {
    let n = unit_vector(ray.point_at_parameter(t) - Vec3::new(0.0, 0.0, -1.0));
    return (Vec3::new(n.x()+1.0, n.y()+1.0, n.z()+1.0)) * 0.5;
  }

  let unit_direction = ray.direction().unit_vector();
  let t = 0.5 * (unit_direction.y() + 1.0);
  return Vec3::new(1.0,1.0,1.0) * (1.0 - t) + Vec3::new(0.5,0.7,1.0) * t;
}

fn main() {
  let nx = 200;
  let ny = 100;
  let data = format!("{}\n{} {}\n{}\n", "P3", nx, ny, 255);
  let f = File::create("target/image.ppm").expect("Unable to create file");
  let mut f = BufWriter::new(f);
  f.write_all(data.as_bytes()).expect("Unable to write data");

  let lower_left_corner = Vec3::new(-2.0, -1.0, -1.0);
  let horizontal = Vec3::new(4.0, 0.0, 0.0);
  let vertical = Vec3::new(0.0, 2.0, 0.0);
  let origin = Vec3::new(0.0, 0.0, 0.0);

  for j in (0..ny).rev() {
    for i in 0..nx {
      let u = i as f64 / nx as f64;
      let v = j as f64 / ny as f64;
      let r = Ray::new(origin, lower_left_corner + horizontal * u + vertical * v);
      let col = color(r);

      let ir = (255.99*col.r()) as i32;
      let ig = (255.99*col.g()) as i32;
      let ib = (255.99*col.b()) as i32;
      f.write_all(format!("{} {} {}\n", ir, ig, ib).as_bytes()).expect("Unable to write data");
    }
  }
}<|endoftext|>


<commit_before>#![feature(fs_walk)]
#![feature(path_ext)]
#![feature(libc)]

extern crate cronparse;
extern crate libc;
extern crate md5;
extern crate users;

#[macro_use]
extern crate log;
extern crate kernlog;

use std::thread::spawn;
use std::env;
use std::fs::{File, PathExt, create_dir_all};
use std::os::unix::fs::symlink;
use std::io::Write;
use std::path::Path;

use cronparse::crontab::{UserCrontabEntry, SystemCrontabEntry, AnacrontabEntry};

mod generate;
mod process;

static USERS_CRONTAB_DIR: &'static str = "/var/spool/cron";  // UserCrontabEntry
static SYSTEM_CRONTAB_DIR: &'static str = "/etc/cron.d";  // SystemCrontabEntry
static ANACRONTAB_FILE: &'static str = "/etc/anacrontab";  // AnacrontabEntry
static REBOOT_FILE: &'static str = "/run/crond.reboot";

macro_rules! try_ {
    ($exp:expr) => {
        match $exp {
            Ok(value) => value,
            Err(err) => { error!("{}", err); return; }
        }
    }
}

fn main() {
    log::set_logger(|filter| kernlog::KernelLog::init_level(log::LogLevelFilter::Error, filter)).unwrap();

    let dest_dir = match env::args().nth(1) {
        None => {
            println!("Usage: systemd-crontab-generator <destination-directory>");
            return;
        },
        Some(path) => path
    };

    let s = dest_dir.clone();
    let user_thread = spawn(|| {
        if Path::new(USERS_CRONTAB_DIR).is_dir() {
            process::process_crontab_dir::<UserCrontabEntry, _>(USERS_CRONTAB_DIR, s);
            if let Err(err) = File::create(REBOOT_FILE) {
                warn!("error creating lock file {}: {}", REBOOT_FILE, err);
            }
        } else {
            let cron_after_var_unit_path = Path::new(&*s).join("cron-after-var.service");
            {
                let mut cron_after_var_unit_file = try_!(File::create(&cron_after_var_unit_path));
                try_!(writeln!(cron_after_var_unit_file, r###"[Unit]
Description=Rerun systemd-crontab-generator because /var is a separate mount
Documentation=man:systemd.cron(7)
After=cron.target
ConditionDirectoryNotEmpty={statedir}

[Service]
Type=oneshot
ExecStart=/bin/sh -c "{bindir}/systemctl daemon-reload ; {bindir}/systemctl try-restart cron.target""###,
                    statedir = USERS_CRONTAB_DIR,
                    bindir = "/usr/bin"));
            }

            let multiuser_wants_path = Path::new(&*s).join("multi-user.target.wants");
            try_!(create_dir_all(&multiuser_wants_path));
            try_!(symlink(cron_after_var_unit_path, multiuser_wants_path.join("cron-after-var.service")));
        }
    });

    let s = dest_dir.clone();
    let system_thread = spawn(|| process::process_crontab_dir::<SystemCrontabEntry, _>(SYSTEM_CRONTAB_DIR, s));

    let s = dest_dir.clone();
    let anacron_thread = spawn(|| process::process_crontab_file::<AnacrontabEntry, _, _>(ANACRONTAB_FILE, s));

    let _ = user_thread.join();
    let _ = system_thread.join();
    let _ = anacron_thread.join();
}
<commit_msg>process /etc/crontab file<commit_after>#![feature(fs_walk)]
#![feature(path_ext)]
#![feature(libc)]

extern crate cronparse;
extern crate libc;
extern crate md5;
extern crate users;

#[macro_use]
extern crate log;
extern crate kernlog;

use std::thread::spawn;
use std::env;
use std::fs::{File, PathExt, create_dir_all};
use std::os::unix::fs::symlink;
use std::io::Write;
use std::path::Path;

use cronparse::crontab::{UserCrontabEntry, SystemCrontabEntry, AnacrontabEntry};

mod generate;
mod process;

static USERS_CRONTAB_DIR: &'static str = "/var/spool/cron";  // UserCrontabEntry
static SYSTEM_CRONTAB_DIR: &'static str = "/etc/cron.d";  // SystemCrontabEntry
static SYSTEM_CRONTAB_FILE: &'static str = "/etc/crontab";
static ANACRONTAB_FILE: &'static str = "/etc/anacrontab";  // AnacrontabEntry
static REBOOT_FILE: &'static str = "/run/crond.reboot";

macro_rules! try_ {
    ($exp:expr) => {
        match $exp {
            Ok(value) => value,
            Err(err) => { error!("{}", err); return; }
        }
    }
}

fn main() {
    log::set_logger(|filter| kernlog::KernelLog::init_level(log::LogLevelFilter::Error, filter)).unwrap();

    let dest_dir = match env::args().nth(1) {
        None => {
            println!("Usage: systemd-crontab-generator <destination-directory>");
            return;
        },
        Some(path) => path
    };

    let s = dest_dir.clone();
    let user_thread = spawn(|| {
        if Path::new(USERS_CRONTAB_DIR).is_dir() {
            process::process_crontab_dir::<UserCrontabEntry, _>(USERS_CRONTAB_DIR, s);
            if let Err(err) = File::create(REBOOT_FILE) {
                warn!("error creating lock file {}: {}", REBOOT_FILE, err);
            }
        } else {
            let cron_after_var_unit_path = Path::new(&*s).join("cron-after-var.service");
            {
                let mut cron_after_var_unit_file = try_!(File::create(&cron_after_var_unit_path));
                try_!(writeln!(cron_after_var_unit_file, r###"[Unit]
Description=Rerun systemd-crontab-generator because /var is a separate mount
Documentation=man:systemd.cron(7)
After=cron.target
ConditionDirectoryNotEmpty={statedir}

[Service]
Type=oneshot
ExecStart=/bin/sh -c "{bindir}/systemctl daemon-reload ; {bindir}/systemctl try-restart cron.target""###,
                    statedir = USERS_CRONTAB_DIR,
                    bindir = "/usr/bin"));
            }

            let multiuser_wants_path = Path::new(&*s).join("multi-user.target.wants");
            try_!(create_dir_all(&multiuser_wants_path));
            try_!(symlink(cron_after_var_unit_path, multiuser_wants_path.join("cron-after-var.service")));
        }
    });

    let s = dest_dir.clone();
    let system_thread = spawn(|| {
        try_!(process::process_crontab_dir::<SystemCrontabEntry, _>(SYSTEM_CRONTAB_DIR, s));
        try_!(process::process_crontab_file::<SystemCrontabEntry, _, _>(SYSTEM_CRONTAB_FILE, s));
    });

    let s = dest_dir.clone();
    let anacron_thread = spawn(|| process::process_crontab_file::<AnacrontabEntry, _, _>(ANACRONTAB_FILE, s));

    let _ = user_thread.join();
    let _ = system_thread.join();
    let _ = anacron_thread.join();
}
<|endoftext|>


<commit_before>extern crate ansi_term;
extern crate argparse;
extern crate hyper;
extern crate libsnatch;

use ansi_term::Colour::{Green, Red};
use argparse::{ArgumentParser, Store, StoreTrue};
use hyper::client::Client;
use libsnatch::Chunks;
use libsnatch::client::GetResponse;
use libsnatch::contentlength::GetContentLength;
use libsnatch::download::download_chunks;
use libsnatch::http_version::ValidateHttpVersion;
use libsnatch::write::write_file;
use std::fs::File;
use std::io;
use std::sync::{Arc, Mutex};
use std::path::Path;
use std::process::exit;

fn main() {

    let mut file = String::from("");
    let mut threads : usize = 4;
    let mut url = String::from("");
    let mut verbose = false;

    {
        let mut argparse = ArgumentParser::new();
        argparse.set_description("Snatch, a simple, fast and interruptable download accelerator, written in Rust.");
        argparse.refer(&mut file)
                .add_option(&["-f", "--file"], Store,
                "The local file to save the remote content file")
                .required();
        argparse.refer(&mut threads)
                .add_option(&["-t", "--threads"], Store,
                "Number of threads available to download");
        argparse.refer(&mut url)
                .add_option(&["-u", "--url"], Store,
                "Remote content URL to download")
                .required();
        argparse.refer(&mut verbose)
                .add_option(&["-v", "--verbose"], StoreTrue,
                "Verbose mode");
        argparse.parse_args_or_exit();
    }

    let hyper_client = Client::new();

    // Get the first response from the server
    let client_response = hyper_client.get_http_response(&url).unwrap();

    print!("# Waiting a response from the remote server... ");

    if ! client_response.version.greater_than_http_11() {
        println!("{}", Red.bold().paint("[ERROR] The version of HTTP requests must be >= HTTP1.1 !"));
        exit(0);
    } else {
        println!("{}", Green.bold().paint("OK !"));
    }

    let local_path = Path::new(&file);

    if local_path.exists() {
        if local_path.is_dir() {
            panic!(Red.bold().paint("[ERROR] The local path to store the remote content is already exists, and is a directory!"));
        }
        println!("{}", Red.bold().paint("[WARNING] The path to store the file already exists! Do you want to override it? [y/N]"));
        {
            let mut user_input = String::new();
            io::stdin().read_line(&mut user_input)
                .ok()
                .expect("[ERROR] Couldn't read line!");
            user_input = String::from(user_input.trim());
            if ! (user_input == "y" || user_input == "Y") {
                exit(0);
            }
        }
    }

    let remote_content_length = match client_response.headers.get_content_length(){
        Some(remote_content_length) => remote_content_length,
        None => {
            println!("{}", Red.bold().paint("[ERROR] Canno't get the content length of the remote content, from the server."));
            exit(1);
        }
    };

    println!("# Remote content length: {:?} bytes", remote_content_length);

    let mut core_chunks = Chunks::with_capacity(threads);

    for _ in 0..threads {
        core_chunks.push(Vec::new());
    }

    let mut shared_chunks = Arc::new(Mutex::new(core_chunks));

    download_chunks(remote_content_length, &mut shared_chunks, threads as u64, &url);

    let mut local_file = File::create(local_path).expect("[ERROR] Canno't create a file !");

    match write_file(&mut local_file, &shared_chunks) {
        Ok(()) => println!("{}", Green.bold().paint("Chunks have been successfuly saved!")),
        Err(error) => println!("[ERROR] {}", error),
    }

}<commit_msg>Update the condition that a file can't be downloaded (using HTTP requests versions)<commit_after>extern crate ansi_term;
extern crate argparse;
extern crate hyper;
extern crate libsnatch;

use ansi_term::Colour::{Green, Yellow, Red};
use argparse::{ArgumentParser, Store, StoreTrue};
use hyper::client::Client;
use libsnatch::Chunks;
use libsnatch::client::GetResponse;
use libsnatch::contentlength::GetContentLength;
use libsnatch::download::download_chunks;
use libsnatch::http_version::ValidateHttpVersion;
use libsnatch::write::write_file;
use std::fs::File;
use std::io;
use std::sync::{Arc, Mutex};
use std::path::Path;
use std::process::exit;

fn main() {

    let mut file = String::from("");
    let mut threads : usize = 4;
    let mut url = String::from("");
    let mut verbose = false;

    {
        let mut argparse = ArgumentParser::new();
        argparse.set_description("Snatch, a simple, fast and interruptable download accelerator, written in Rust.");
        argparse.refer(&mut file)
                .add_option(&["-f", "--file"], Store,
                "The local file to save the remote content file")
                .required();
        argparse.refer(&mut threads)
                .add_option(&["-t", "--threads"], Store,
                "Number of threads available to download");
        argparse.refer(&mut url)
                .add_option(&["-u", "--url"], Store,
                "Remote content URL to download")
                .required();
        argparse.refer(&mut verbose)
                .add_option(&["-v", "--verbose"], StoreTrue,
                "Verbose mode");
        argparse.parse_args_or_exit();
    }

    let hyper_client = Client::new();

    // Get the first response from the server
    let client_response = hyper_client.get_http_response(&url).unwrap();

    print!("# Waiting a response from the remote server... ");

    if !client_response.version.greater_than_http_11() {
        println!("{}",
                 Yellow.bold()
                     .paint("[WARNING] The version of HTTP requests is <= HTTP1.0 - it can be \
                             difficult to split efficiently the remote content!"));
    } else {
        println!("{}", Green.bold().paint("OK !"));
    }

    let local_path = Path::new(&file);

    if local_path.exists() {
        if local_path.is_dir() {
            panic!(Red.bold().paint("[ERROR] The local path to store the remote content is already exists, and is a directory!"));
        }
        println!("{}", Red.bold().paint("[WARNING] The path to store the file already exists! Do you want to override it? [y/N]"));
        {
            let mut user_input = String::new();
            io::stdin().read_line(&mut user_input)
                .ok()
                .expect("[ERROR] Couldn't read line!");
            user_input = String::from(user_input.trim());
            if ! (user_input == "y" || user_input == "Y") {
                exit(0);
            }
        }
    }

    let remote_content_length = match client_response.headers.get_content_length(){
        Some(remote_content_length) => remote_content_length,
        None => {
            println!("{}", Red.bold().paint("[ERROR] Canno't get the content length of the remote content, from the server."));
            exit(1);
        }
    };

    println!("# Remote content length: {:?} bytes", remote_content_length);

    let mut core_chunks = Chunks::with_capacity(threads);

    for _ in 0..threads {
        core_chunks.push(Vec::new());
    }

    let mut shared_chunks = Arc::new(Mutex::new(core_chunks));

    download_chunks(remote_content_length, &mut shared_chunks, threads as u64, &url);

    let mut local_file = File::create(local_path).expect("[ERROR] Canno't create a file !");

    match write_file(&mut local_file, &shared_chunks) {
        Ok(()) => println!("{}", Green.bold().paint("Chunks have been successfuly saved!")),
        Err(error) => println!("[ERROR] {}", error),
    }

}<|endoftext|>


<commit_before>extern crate discord;

use discord::{Discord, ChannelRef, State};
use discord::voice::AudioReceiver;
use discord::model::{Event, UserId, ChannelType};
use std::env;

struct VoiceTest;

impl AudioReceiver for VoiceTest {
	fn speaking_update(&mut self, ssrc: u32, user_id: UserId, speaking: bool) {
		println!("[{}] is {:?} -> {}", ssrc, user_id, speaking);
	}

	fn voice_packet(&mut self, ssrc: u32, sequence: u16, timestamp: u32, stereo: bool, _data: &[i16]) {
		println!("[{}] ({}, {}) stereo = {}", ssrc, sequence, timestamp, stereo);
	}
}

pub fn main() {
	// Log in to Discord using a bot token from the environment
	let discord = Discord::from_bot_token(
		&env::var("DISCORD_TOKEN").expect("Expected token"),
	).expect("login failed");

	// Establish and use a websocket connection
	let (mut connection, ready) = discord.connect().expect("connect failed");
	let mut state = State::new(ready);
	let channel_count: usize = state.servers().iter()
		.map(|srv| srv.channels.iter()
			.filter(|chan| chan.kind == ChannelType::Text)
			.count()
		).fold(0, |v, s| v + s);
	println!("[Ready] {} logging {} servers with {} text channels", state.user().username, state.servers().len(), channel_count);

	loop {
		match connection.recv_event() {
			Ok(Event::MessageCreate(message)) => {
				println!("{} says: {}", message.author.name, message.content);
				if message.content == "!test" {
					let _ = discord.send_message(message.channel_id, "This is a reply to the test.", "", false);
				} else if message.content == "!quit" {
					    println!("Quitting.");
					    break
                }
                if message.content == "!help" {
                    let _ = discord.send_message(message.channel_id, "I can't help you. I'm just a bot.", "", false);
                }
                if message.content == "!about" {
                    let _ = discord.send_message(message.channel_id, "I have no clue. All I know is that I was written by Arroz in a language called Rust, and my code is still being developed.", "", false);
                }
                if message.content == "!uber" {
                    let _ = discord.send_message(message.channel_id, "Fuck off m8.", "", false);
                }
                if message.content == "!ask" {
                    let _ = discord.send_message(message.channel_id, "Not just yet, I'll have the answers soon.", "", false);
                }

			}

			Ok(_) => {}
			Err(discord::Error::Closed(code, body)) => {
				println!("Gateway closed on us with code {:?}: {}", code, body);
				break
			}
			Err(err) => println!("Receive error: {:?}", err)
		}
	}
}
<commit_msg>added command<commit_after>extern crate discord;

use discord::{Discord, ChannelRef, State};
use discord::voice::AudioReceiver;
use discord::model::{Event, UserId, ChannelType};
use std::env;

struct VoiceTest;

impl AudioReceiver for VoiceTest {
	fn speaking_update(&mut self, ssrc: u32, user_id: UserId, speaking: bool) {
		println!("[{}] is {:?} -> {}", ssrc, user_id, speaking);
	}

	fn voice_packet(&mut self, ssrc: u32, sequence: u16, timestamp: u32, stereo: bool, _data: &[i16]) {
		println!("[{}] ({}, {}) stereo = {}", ssrc, sequence, timestamp, stereo);
	}
}

pub fn main() {
	// Log in to Discord using a bot token from the environment
	let discord = Discord::from_bot_token(
		&env::var("DISCORD_TOKEN").expect("Expected token"),
	).expect("login failed");

	// Establish and use a websocket connection
	let (mut connection, ready) = discord.connect().expect("connect failed");
	let mut state = State::new(ready);
	let channel_count: usize = state.servers().iter()
		.map(|srv| srv.channels.iter()
			.filter(|chan| chan.kind == ChannelType::Text)
			.count()
		).fold(0, |v, s| v + s);
	println!("[Ready] {} logging {} servers with {} text channels", state.user().username, state.servers().len(), channel_count);

	loop {
		match connection.recv_event() {
			Ok(Event::MessageCreate(message)) => {
				println!("{} says: {}", message.author.name, message.content);
				if message.content == "!test" {
					let _ = discord.send_message(message.channel_id, "This is a reply to the test.", "", false);
				} else if message.content == "!quit" {
					    println!("Quitting.");
					    break
                }
                if message.content == "!help" {
                    let _ = discord.send_message(message.channel_id, "I can't help you. I'm just a bot.", "", false);
                }
                if message.content == "!about" {
                    let _ = discord.send_message(message.channel_id, "I have no clue. All I know is that I was written by Arroz in a language called Rust, and my code is still being developed.", "", false);
                }
                if message.content == "!uber" {
                    let _ = discord.send_message(message.channel_id, "Fuck off m8.", "", false);
                }
                if message.content == "!ask" {
                    let _ = discord.send_message(message.channel_id, "Not just yet, I'll have the answers soon.", "", false);
                }
				if message.content == "!givemeyourcode" {
					let _ = discord.send_message(message.channel_id, "Okay, here you go. https://github.com/aarroz/rice_bot2")
				}

			}

			Ok(_) => {}
			Err(discord::Error::Closed(code, body)) => {
				println!("Gateway closed on us with code {:?}: {}", code, body);
				break
			}
			Err(err) => println!("Receive error: {:?}", err)
		}
	}
}
<|endoftext|>


<commit_before>extern crate iron;
extern crate hyper_native_tls;

use iron::mime::{Mime, TopLevel, SubLevel};
use iron::headers::ContentType;

fn main() {
    // Avoid unused errors due to conditional compilation ('native-tls-example' feature is not default)
    use hyper_native_tls::NativeTlsServer;
    use iron::{Iron, Request, Response};
    use iron::status;
    use std::result::Result;

    let ssl = NativeTlsServer::new("identity.p12", "mypass").unwrap();

    match Iron::new(|_: &mut Request| {
        println!("Got an incoming connection!");
        let mut response = Response::with((status::Ok, "
Hello world!
"));
        response.headers.set(ContentType(Mime(TopLevel::Text, SubLevel::Html, vec![])));
        Ok(response)
    }).https("127.0.0.1:3000", ssl) {
        Result::Ok(listening) => println!("{:?}", listening),
        Result::Err(err) => panic!("{:?}", err),
    }
    // curl -vvvv https://127.0.0.1:3000/ -k
}<commit_msg>Deus est mortus, logica optinet<commit_after>extern crate iron;
extern crate hyper_native_tls;

use iron::mime::{Mime, TopLevel, SubLevel};
use iron::headers::ContentType;
use iron::{Iron, Request, Response, method};
use iron::status;
use std::result::Result;

fn main() {
    match Iron::new(|request: &mut Request| {
        println!("Got an incoming connection!");
        let mut response = Response::with((status::Ok, "
Hello world!

:)"));
        response.headers.set(ContentType(Mime(TopLevel::Text, SubLevel::Html, vec![])));
        Ok(response)
    }).http("127.0.0.1:8080") {
        Result::Ok(listening) => println!("{:?}", listening),
        Result::Err(err) => panic!("{:?}", err),
    }
}
<|endoftext|>


<commit_before>extern crate docopt;
extern crate rustc_serialize;
extern crate kafka;

use docopt::Docopt;
use kafka::client::KafkaClient;

// usage string
static USAGE: &'static str = "
kcat - cat for Kafka.

Usage:
    kcat [-b BROKER] -t TOPIC
    kcat (-h | --help)

Options:
    -h, --help                  Show this message.
    -b BROKER, --broker=BROKER  Kafka broker [default: localhost:9092].
    -t TOPIC, --topic=TOPIC     Kafka topic.
";

#[derive(RustcDecodable, Debug)]
struct Args {
    flag_broker: String,
    flag_topic: String,
}

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

    let mut client = KafkaClient::new(vec!(args.flag_broker));
    let meta_res = client.load_metadata_all();
    if meta_res.is_err() {
        match meta_res.err() {
            Some(err) => println!("Error: {}", err),
            None => println!("Non-specific error")
        }
        return;
    }

    let mut prev_offset:i64 = -1;
    loop {
        let res = client.fetch_messages(
            args.flag_topic.to_string(), // topic
            0,                           // partition
            prev_offset + 1              // offset
        );
        if res.is_ok() {
            for tmsg in res.unwrap() {
                println!("{}", String::from_utf8(tmsg.message).unwrap());
                prev_offset = tmsg.offset;
            }
        }
    }
}
<commit_msg>Discovered let Some pattern and putting it to use<commit_after>extern crate docopt;
extern crate rustc_serialize;
extern crate kafka;

use docopt::Docopt;
use kafka::client::KafkaClient;

// usage string
static USAGE: &'static str = "
kcat - cat for Kafka.

Usage:
    kcat [-b BROKER] -t TOPIC
    kcat (-h | --help)

Options:
    -h, --help                  Show this message.
    -b BROKER, --broker=BROKER  Kafka broker [default: localhost:9092].
    -t TOPIC, --topic=TOPIC     Kafka topic.
";

#[derive(RustcDecodable, Debug)]
struct Args {
    flag_broker: String,
    flag_topic: String,
}

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

    let mut client = KafkaClient::new(vec!(args.flag_broker));
    let meta_res = client.load_metadata_all();
    if let Some(err) = meta_res.err() {
        println!("Error fetching metadata: {}", err);
        return;
    }

    let mut prev_offset:i64 = -1;
    loop {
        let res = client.fetch_messages(
            args.flag_topic.to_string(), // topic
            0,                           // partition
            prev_offset + 1              // offset
        );
        if res.is_ok() {
            for tmsg in res.unwrap() {
                println!("{}", String::from_utf8(tmsg.message).unwrap());
                prev_offset = tmsg.offset;
            }
        }
    }
}
<|endoftext|>


<commit_before>#[macro_use]
mod error;

mod app;
mod exec;
mod exit_codes;
mod filesystem;
mod filetypes;
mod filter;
mod options;
mod output;
mod regex_helper;
mod walk;

use std::env;
use std::path::{Path, PathBuf};
use std::process;
use std::sync::Arc;
use std::time;

use atty::Stream;
use globset::Glob;
use lscolors::LsColors;
use regex::bytes::{RegexBuilder, RegexSetBuilder};

use crate::exec::CommandTemplate;
use crate::filetypes::FileTypes;
use crate::filter::{SizeFilter, TimeFilter};
use crate::options::Options;
use crate::regex_helper::pattern_has_uppercase_char;

// We use jemalloc for performance reasons, see https://github.com/sharkdp/fd/pull/481
#[cfg(all(not(windows), not(target_env = "musl")))]
#[global_allocator]
static ALLOC: jemallocator::Jemalloc = jemallocator::Jemalloc;

fn main() {
    let matches = app::build_app().get_matches_from(env::args_os());

    // Set the current working directory of the process
    if let Some(base_directory) = matches.value_of("base-directory") {
        let basedir = Path::new(base_directory);
        if !filesystem::is_dir(basedir) {
            print_error_and_exit!(
                "The '--base-directory' path ('{}') is not a directory.",
                basedir.to_string_lossy()
            );
        }
        if let Err(e) = env::set_current_dir(basedir) {
            print_error_and_exit!(
                "Could not set '{}' as the current working directory: {}",
                basedir.to_string_lossy(),
                e
            );
        }
    }

    // Get the search pattern
    let pattern = matches.value_of("pattern").unwrap_or("");

    // Get the current working directory
    let current_dir = Path::new(".");
    if !filesystem::is_dir(current_dir) {
        print_error_and_exit!("Could not get current directory.");
    }

    // Get one or more root directories to search.
    let mut dir_vec: Vec<_> = match matches
        .values_of("path")
        .or_else(|| matches.values_of("search-path"))
    {
        Some(paths) => paths
            .map(|path| {
                let path_buffer = PathBuf::from(path);
                if !filesystem::is_dir(&path_buffer) {
                    print_error_and_exit!(
                        "'{}' is not a directory.",
                        path_buffer.to_string_lossy()
                    );
                }
                path_buffer
            })
            .collect::<Vec<_>>(),
        None => vec![current_dir.to_path_buf()],
    };

    if matches.is_present("absolute-path") {
        dir_vec = dir_vec
            .iter()
            .map(|path_buffer| {
                path_buffer
                    .canonicalize()
                    .and_then(|pb| filesystem::absolute_path(pb.as_path()))
                    .unwrap()
            })
            .collect();
    }

    // Detect if the user accidentally supplied a path instead of a search pattern
    if !matches.is_present("full-path")
        && pattern.contains(std::path::MAIN_SEPARATOR)
        && filesystem::is_dir(Path::new(pattern))
    {
        print_error_and_exit!(
            "The search pattern '{pattern}' contains a path-separation character ('{sep}') \
             and will not lead to any search results.\n\n\
             If you want to search for all files inside the '{pattern}' directory, use a match-all pattern:\n\n  \
             fd . '{pattern}'\n\n\
             Instead, if you want to search for the pattern in the full path, use:\n\n  \
             fd --full-path '{pattern}'",
            pattern = pattern,
            sep = std::path::MAIN_SEPARATOR,
        );
    }

    let pattern_regex = if matches.is_present("glob") {
        let glob = match Glob::new(pattern) {
            Ok(glob) => glob,
            Err(e) => {
                print_error_and_exit!("{}", e);
            }
        };
        glob.regex().to_owned()
    } else if matches.is_present("fixed-strings") {
        // Treat pattern as literal string if '--fixed-strings' is used
        regex::escape(pattern)
    } else {
        String::from(pattern)
    };

    // The search will be case-sensitive if the command line flag is set or
    // if the pattern has an uppercase character (smart case).
    let case_sensitive = !matches.is_present("ignore-case")
        && (matches.is_present("case-sensitive") || pattern_has_uppercase_char(&pattern_regex));

    let colored_output = match matches.value_of("color") {
        Some("always") => true,
        Some("never") => false,
        _ => env::var_os("NO_COLOR").is_none() && atty::is(Stream::Stdout),
    };

    let path_separator = matches.value_of("path-separator").map(|str| str.to_owned());

    #[cfg(windows)]
    let colored_output = colored_output && ansi_term::enable_ansi_support().is_ok();

    let ls_colors = if colored_output {
        Some(LsColors::from_env().unwrap_or_default())
    } else {
        None
    };

    let command = matches
        .values_of("exec")
        .map(CommandTemplate::new)
        .or_else(|| {
            matches.values_of("exec-batch").map(|m| {
                CommandTemplate::new_batch(m).unwrap_or_else(|e| {
                    print_error_and_exit!("{}", e);
                })
            })
        })
        .or_else(|| {
            if matches.is_present("list-details") {
                let color = matches.value_of("color").unwrap_or("auto");
                let color_arg = ["--color=", color].concat();

                Some(
                    CommandTemplate::new_batch(&[
                        "ls",
                        "-l",               // long listing format
                        "--human-readable", // human readable file sizes
                        "--directory",      // list directories themselves, not their contents
                        &color_arg,         // enable colorized output, if enabled
                    ])
                    .unwrap(),
                )
            } else {
                None
            }
        });

    let size_limits: Vec<SizeFilter> = matches
        .values_of("size")
        .map(|v| {
            v.map(|sf| {
                if let Some(f) = SizeFilter::from_string(sf) {
                    return f;
                }
                print_error_and_exit!("'{}' is not a valid size constraint. See 'fd --help'.", sf);
            })
            .collect()
        })
        .unwrap_or_else(|| vec![]);

    let now = time::SystemTime::now();
    let mut time_constraints: Vec<TimeFilter> = Vec::new();
    if let Some(t) = matches.value_of("changed-within") {
        if let Some(f) = TimeFilter::after(&now, t) {
            time_constraints.push(f);
        } else {
            print_error_and_exit!("'{}' is not a valid date or duration. See 'fd --help'.", t);
        }
    }
    if let Some(t) = matches.value_of("changed-before") {
        if let Some(f) = TimeFilter::before(&now, t) {
            time_constraints.push(f);
        } else {
            print_error_and_exit!("'{}' is not a valid date or duration. See 'fd --help'.", t);
        }
    }

    let config = Options {
        case_sensitive,
        search_full_path: matches.is_present("full-path"),
        ignore_hidden: !(matches.is_present("hidden")
            || matches.occurrences_of("rg-alias-hidden-ignore") >= 2),
        read_fdignore: !(matches.is_present("no-ignore")
            || matches.is_present("rg-alias-hidden-ignore")),
        read_vcsignore: !(matches.is_present("no-ignore")
            || matches.is_present("rg-alias-hidden-ignore")
            || matches.is_present("no-ignore-vcs")),
        follow_links: matches.is_present("follow"),
        one_file_system: matches.is_present("one-file-system"),
        null_separator: matches.is_present("null_separator"),
        max_depth: matches
            .value_of("depth")
            .or_else(|| matches.value_of("rg-depth"))
            .and_then(|n| usize::from_str_radix(n, 10).ok()),
        threads: std::cmp::max(
            matches
                .value_of("threads")
                .and_then(|n| usize::from_str_radix(n, 10).ok())
                .unwrap_or_else(num_cpus::get),
            1,
        ),
        max_buffer_time: matches
            .value_of("max-buffer-time")
            .and_then(|n| u64::from_str_radix(n, 10).ok())
            .map(time::Duration::from_millis),
        ls_colors,
        file_types: matches.values_of("file-type").map(|values| {
            let mut file_types = FileTypes::default();
            for value in values {
                match value {
                    "f" | "file" => file_types.files = true,
                    "d" | "directory" => file_types.directories = true,
                    "l" | "symlink" => file_types.symlinks = true,
                    "x" | "executable" => {
                        file_types.executables_only = true;
                        file_types.files = true;
                    }
                    "e" | "empty" => {
                        file_types.empty_only = true;
                    }
                    _ => unreachable!(),
                }
            }

            // If only 'empty' was specified, search for both files and directories:
            if file_types.empty_only && !(file_types.files || file_types.directories) {
                file_types.files = true;
                file_types.directories = true;
            }

            file_types
        }),
        extensions: matches.values_of("extension").map(|exts| {
            let patterns = exts
                .map(|e| e.trim_start_matches('.'))
                .map(|e| format!(r".\.{}$", regex::escape(e)));
            match RegexSetBuilder::new(patterns)
                .case_insensitive(true)
                .build()
            {
                Ok(re) => re,
                Err(err) => {
                    print_error_and_exit!("{}", err.to_string());
                }
            }
        }),
        command: command.map(Arc::new),
        exclude_patterns: matches
            .values_of("exclude")
            .map(|v| v.map(|p| String::from("!") + p).collect())
            .unwrap_or_else(|| vec![]),
        ignore_files: matches
            .values_of("ignore-file")
            .map(|vs| vs.map(PathBuf::from).collect())
            .unwrap_or_else(|| vec![]),
        size_constraints: size_limits,
        time_constraints,
        show_filesystem_errors: matches.is_present("show-errors"),
        path_separator,
        max_results: matches
            .value_of("max-results")
            .and_then(|n| usize::from_str_radix(n, 10).ok())
            .filter(|&n| n != 0),
    };

    match RegexBuilder::new(&pattern_regex)
        .case_insensitive(!config.case_sensitive)
        .dot_matches_new_line(true)
        .build()
    {
        Ok(re) => {
            let exit_code = walk::scan(&dir_vec, Arc::new(re), Arc::new(config));
            process::exit(exit_code.into());
        }
        Err(err) => {
            print_error_and_exit!(
                "{}\nHint: You can use the '--fixed-strings' option to search for a \
                 literal string instead of a regular expression",
                err.to_string()
            );
        }
    }
}
<commit_msg>Refactor directory handling<commit_after>#[macro_use]
mod error;

mod app;
mod exec;
mod exit_codes;
mod filesystem;
mod filetypes;
mod filter;
mod options;
mod output;
mod regex_helper;
mod walk;

use std::env;
use std::path::{Path, PathBuf};
use std::process;
use std::sync::Arc;
use std::time;

use atty::Stream;
use globset::Glob;
use lscolors::LsColors;
use regex::bytes::{RegexBuilder, RegexSetBuilder};

use crate::exec::CommandTemplate;
use crate::filetypes::FileTypes;
use crate::filter::{SizeFilter, TimeFilter};
use crate::options::Options;
use crate::regex_helper::pattern_has_uppercase_char;

// We use jemalloc for performance reasons, see https://github.com/sharkdp/fd/pull/481
#[cfg(all(not(windows), not(target_env = "musl")))]
#[global_allocator]
static ALLOC: jemallocator::Jemalloc = jemallocator::Jemalloc;

fn main() {
    let matches = app::build_app().get_matches_from(env::args_os());

    // Set the current working directory of the process
    if let Some(base_directory) = matches.value_of("base-directory") {
        let base_directory = Path::new(base_directory);
        if !filesystem::is_dir(base_directory) {
            print_error_and_exit!(
                "The '--base-directory' path ('{}') is not a directory.",
                base_directory.to_string_lossy()
            );
        }
        if let Err(e) = env::set_current_dir(base_directory) {
            print_error_and_exit!(
                "Could not set '{}' as the current working directory: {}",
                base_directory.to_string_lossy(),
                e
            );
        }
    }

    let current_directory = Path::new(".");
    if !filesystem::is_dir(current_directory) {
        print_error_and_exit!("Could not get current directory.");
    }

    // Get the search pattern
    let pattern = matches.value_of("pattern").unwrap_or("");

    // Get one or more root directories to search.
    let mut dir_vec: Vec<_> = match matches
        .values_of("path")
        .or_else(|| matches.values_of("search-path"))
    {
        Some(paths) => paths
            .map(|path| {
                let path_buffer = PathBuf::from(path);
                if !filesystem::is_dir(&path_buffer) {
                    print_error_and_exit!(
                        "'{}' is not a directory.",
                        path_buffer.to_string_lossy()
                    );
                }
                path_buffer
            })
            .collect::<Vec<_>>(),
        None => vec![current_directory.to_path_buf()],
    };

    if matches.is_present("absolute-path") {
        dir_vec = dir_vec
            .iter()
            .map(|path_buffer| {
                path_buffer
                    .canonicalize()
                    .and_then(|pb| filesystem::absolute_path(pb.as_path()))
                    .unwrap()
            })
            .collect();
    }

    // Detect if the user accidentally supplied a path instead of a search pattern
    if !matches.is_present("full-path")
        && pattern.contains(std::path::MAIN_SEPARATOR)
        && filesystem::is_dir(Path::new(pattern))
    {
        print_error_and_exit!(
            "The search pattern '{pattern}' contains a path-separation character ('{sep}') \
             and will not lead to any search results.\n\n\
             If you want to search for all files inside the '{pattern}' directory, use a match-all pattern:\n\n  \
             fd . '{pattern}'\n\n\
             Instead, if you want to search for the pattern in the full path, use:\n\n  \
             fd --full-path '{pattern}'",
            pattern = pattern,
            sep = std::path::MAIN_SEPARATOR,
        );
    }

    let pattern_regex = if matches.is_present("glob") {
        let glob = match Glob::new(pattern) {
            Ok(glob) => glob,
            Err(e) => {
                print_error_and_exit!("{}", e);
            }
        };
        glob.regex().to_owned()
    } else if matches.is_present("fixed-strings") {
        // Treat pattern as literal string if '--fixed-strings' is used
        regex::escape(pattern)
    } else {
        String::from(pattern)
    };

    // The search will be case-sensitive if the command line flag is set or
    // if the pattern has an uppercase character (smart case).
    let case_sensitive = !matches.is_present("ignore-case")
        && (matches.is_present("case-sensitive") || pattern_has_uppercase_char(&pattern_regex));

    let colored_output = match matches.value_of("color") {
        Some("always") => true,
        Some("never") => false,
        _ => env::var_os("NO_COLOR").is_none() && atty::is(Stream::Stdout),
    };

    let path_separator = matches.value_of("path-separator").map(|str| str.to_owned());

    #[cfg(windows)]
    let colored_output = colored_output && ansi_term::enable_ansi_support().is_ok();

    let ls_colors = if colored_output {
        Some(LsColors::from_env().unwrap_or_default())
    } else {
        None
    };

    let command = matches
        .values_of("exec")
        .map(CommandTemplate::new)
        .or_else(|| {
            matches.values_of("exec-batch").map(|m| {
                CommandTemplate::new_batch(m).unwrap_or_else(|e| {
                    print_error_and_exit!("{}", e);
                })
            })
        })
        .or_else(|| {
            if matches.is_present("list-details") {
                let color = matches.value_of("color").unwrap_or("auto");
                let color_arg = ["--color=", color].concat();

                Some(
                    CommandTemplate::new_batch(&[
                        "ls",
                        "-l",               // long listing format
                        "--human-readable", // human readable file sizes
                        "--directory",      // list directories themselves, not their contents
                        &color_arg,         // enable colorized output, if enabled
                    ])
                    .unwrap(),
                )
            } else {
                None
            }
        });

    let size_limits: Vec<SizeFilter> = matches
        .values_of("size")
        .map(|v| {
            v.map(|sf| {
                if let Some(f) = SizeFilter::from_string(sf) {
                    return f;
                }
                print_error_and_exit!("'{}' is not a valid size constraint. See 'fd --help'.", sf);
            })
            .collect()
        })
        .unwrap_or_else(|| vec![]);

    let now = time::SystemTime::now();
    let mut time_constraints: Vec<TimeFilter> = Vec::new();
    if let Some(t) = matches.value_of("changed-within") {
        if let Some(f) = TimeFilter::after(&now, t) {
            time_constraints.push(f);
        } else {
            print_error_and_exit!("'{}' is not a valid date or duration. See 'fd --help'.", t);
        }
    }
    if let Some(t) = matches.value_of("changed-before") {
        if let Some(f) = TimeFilter::before(&now, t) {
            time_constraints.push(f);
        } else {
            print_error_and_exit!("'{}' is not a valid date or duration. See 'fd --help'.", t);
        }
    }

    let config = Options {
        case_sensitive,
        search_full_path: matches.is_present("full-path"),
        ignore_hidden: !(matches.is_present("hidden")
            || matches.occurrences_of("rg-alias-hidden-ignore") >= 2),
        read_fdignore: !(matches.is_present("no-ignore")
            || matches.is_present("rg-alias-hidden-ignore")),
        read_vcsignore: !(matches.is_present("no-ignore")
            || matches.is_present("rg-alias-hidden-ignore")
            || matches.is_present("no-ignore-vcs")),
        follow_links: matches.is_present("follow"),
        one_file_system: matches.is_present("one-file-system"),
        null_separator: matches.is_present("null_separator"),
        max_depth: matches
            .value_of("depth")
            .or_else(|| matches.value_of("rg-depth"))
            .and_then(|n| usize::from_str_radix(n, 10).ok()),
        threads: std::cmp::max(
            matches
                .value_of("threads")
                .and_then(|n| usize::from_str_radix(n, 10).ok())
                .unwrap_or_else(num_cpus::get),
            1,
        ),
        max_buffer_time: matches
            .value_of("max-buffer-time")
            .and_then(|n| u64::from_str_radix(n, 10).ok())
            .map(time::Duration::from_millis),
        ls_colors,
        file_types: matches.values_of("file-type").map(|values| {
            let mut file_types = FileTypes::default();
            for value in values {
                match value {
                    "f" | "file" => file_types.files = true,
                    "d" | "directory" => file_types.directories = true,
                    "l" | "symlink" => file_types.symlinks = true,
                    "x" | "executable" => {
                        file_types.executables_only = true;
                        file_types.files = true;
                    }
                    "e" | "empty" => {
                        file_types.empty_only = true;
                    }
                    _ => unreachable!(),
                }
            }

            // If only 'empty' was specified, search for both files and directories:
            if file_types.empty_only && !(file_types.files || file_types.directories) {
                file_types.files = true;
                file_types.directories = true;
            }

            file_types
        }),
        extensions: matches.values_of("extension").map(|exts| {
            let patterns = exts
                .map(|e| e.trim_start_matches('.'))
                .map(|e| format!(r".\.{}$", regex::escape(e)));
            match RegexSetBuilder::new(patterns)
                .case_insensitive(true)
                .build()
            {
                Ok(re) => re,
                Err(err) => {
                    print_error_and_exit!("{}", err.to_string());
                }
            }
        }),
        command: command.map(Arc::new),
        exclude_patterns: matches
            .values_of("exclude")
            .map(|v| v.map(|p| String::from("!") + p).collect())
            .unwrap_or_else(|| vec![]),
        ignore_files: matches
            .values_of("ignore-file")
            .map(|vs| vs.map(PathBuf::from).collect())
            .unwrap_or_else(|| vec![]),
        size_constraints: size_limits,
        time_constraints,
        show_filesystem_errors: matches.is_present("show-errors"),
        path_separator,
        max_results: matches
            .value_of("max-results")
            .and_then(|n| usize::from_str_radix(n, 10).ok())
            .filter(|&n| n != 0),
    };

    match RegexBuilder::new(&pattern_regex)
        .case_insensitive(!config.case_sensitive)
        .dot_matches_new_line(true)
        .build()
    {
        Ok(re) => {
            let exit_code = walk::scan(&dir_vec, Arc::new(re), Arc::new(config));
            process::exit(exit_code.into());
        }
        Err(err) => {
            print_error_and_exit!(
                "{}\nHint: You can use the '--fixed-strings' option to search for a \
                 literal string instead of a regular expression",
                err.to_string()
            );
        }
    }
}
<|endoftext|>