<commit_before>#![deny(warnings)]

extern crate chan;
extern crate crypto;
extern crate walkdir;

use self::crypto::digest::Digest;
use self::crypto::sha1::Sha1;
use std::env;
use std::fs::File;
use std::io::Read;
use std::io;
use std::path::Path;
use std::sync::Arc;
use std::thread;
use walkdir::DirEntry;
use walkdir::WalkDir;

/// The purpose of this newtype is to hide the channel.
struct GatherIter<T>(chan::Iter<T>);
impl<T> Iterator for GatherIter<T> {
    type Item = T;
    fn next(&mut self) -> Option<T> {
        self.0.next()
    }
}

/// producer_ctor and xform_ctor is needed to allow construction
/// in the correct producer / worker thread.
/// TODO: Figure out how to simplify this trait mess :)
fn scatter_gather<PC, XC, P, X, J, R>(producer_ctor: PC, xform_ctor: XC) -> GatherIter<R>
    where PC: 'static + std::marker::Send + FnOnce() -> P,
          XC: 'static + std::marker::Send + std::marker::Sync + Fn() -> X,
          X: FnMut(J) -> R,
          J: 'static + std::marker::Send,
          R: 'static + std::marker::Send,
          P: IntoIterator<Item = J>
{
    let jobs_rx = {
        let (tx, rx) = chan::sync(0);
        thread::spawn(move || {
            for e in producer_ctor().into_iter() {
                tx.send(e);
            }
        });
        rx
    };
    let results_rx = {
        let (tx, rx) = chan::sync(0);
        let xform_ctor = Arc::new(xform_ctor); // TODO: Investigate why this is needed.
        // TODO: Find and use a num_cpu function.
        for _ in 0..8 {
            let tx = tx.clone();
            let jobs_rx = jobs_rx.clone();
            let xform_ctor = xform_ctor.clone();
            thread::spawn(move || {
                let mut xform = xform_ctor();
                for e in jobs_rx {
                    tx.send(xform(e));
                }
            });
        }
        rx
    };
    GatherIter(results_rx.iter())
}

fn calc_hash(p: &Path, hasher: &mut Sha1, buf: &mut [u8]) -> io::Result<String> {
    hasher.reset();
    let mut f = File::open(p)?;
    loop {
        let num_read = f.read(buf)?;
        if num_read == 0 {
            break;
        }
        hasher.input(&buf[..num_read]);
    }
    Ok(hasher.result_str())
}

type Result<T> = std::result::Result<T, Error>;

#[derive(Debug)]
enum Error {
    Io(io::Error),
    Ignored(DirEntry),
    WalkDir(walkdir::Error),
}

fn process_root(root: &Path) -> io::Result<()> {
    let pb = root.to_path_buf();
    let producer_ctor = || WalkDir::new(pb);
    let xform_ctor = || {
        let mut hasher = Sha1::new();
        let mut buf = [0; 1024 * 8];
        let f = move |e: walkdir::Result<DirEntry>| -> Result<String> {
            let e = e.map_err(Error::WalkDir)?;
            if !e.file_type().is_file() {
                return Err(Error::Ignored(e));
            }
            calc_hash(e.path(), &mut hasher, &mut buf).map_err(Error::Io)
        };
        f
    };
    let results = scatter_gather(producer_ctor, xform_ctor);
    for r in results {
        println!("{:?}", r);
    }
    Ok(())
}

fn main() {
    let root = env::args().nth(1).unwrap_or(".".to_string());
    let root = Path::new(root.as_str());
    process_root(root).expect("Hello error 2!");
}
<commit_msg>Trait naming cleanup.<commit_after>#![deny(warnings)]

extern crate chan;
extern crate crypto;
extern crate walkdir;

use self::crypto::digest::Digest;
use self::crypto::sha1::Sha1;
use std::env;
use std::fs::File;
use std::io::Read;
use std::io;
use std::marker::Send;
use std::marker::Sync;
use std::path::Path;
use std::sync::Arc;
use std::thread;
use walkdir::DirEntry;
use walkdir::WalkDir;

/// The purpose of this newtype is to hide the channel.
struct GatherIter<T>(chan::Iter<T>);
impl<T> Iterator for GatherIter<T> {
    type Item = T;
    fn next(&mut self) -> Option<T> {
        self.0.next()
    }
}

/// producer_ctor and xform_ctor is needed to allow construction
/// in the correct producer / worker thread.
/// TODO: Figure out how to simplify this trait mess :)
fn scatter_gather<PC, XC, P, X, J, R>(producer_ctor: PC, xform_ctor: XC) -> GatherIter<R>
    where PC: 'static + Send + FnOnce() -> P,
          XC: 'static + Send + Sync + Fn() -> X,
          X: FnMut(J) -> R,
          J: 'static + Send,
          R: 'static + Send,
          P: IntoIterator<Item = J>
{
    let jobs_rx = {
        let (tx, rx) = chan::sync(0);
        thread::spawn(move || {
            for e in producer_ctor().into_iter() {
                tx.send(e);
            }
        });
        rx
    };
    let results_rx = {
        let (tx, rx) = chan::sync(0);
        let xform_ctor = Arc::new(xform_ctor); // TODO: Investigate why this is needed.
        // TODO: Find and use a num_cpu function.
        for _ in 0..8 {
            let tx = tx.clone();
            let jobs_rx = jobs_rx.clone();
            let xform_ctor = xform_ctor.clone();
            thread::spawn(move || {
                let mut xform = xform_ctor();
                for e in jobs_rx {
                    tx.send(xform(e));
                }
            });
        }
        rx
    };
    GatherIter(results_rx.iter())
}

fn calc_hash(p: &Path, hasher: &mut Sha1, buf: &mut [u8]) -> io::Result<String> {
    hasher.reset();
    let mut f = File::open(p)?;
    loop {
        let num_read = f.read(buf)?;
        if num_read == 0 {
            break;
        }
        hasher.input(&buf[..num_read]);
    }
    Ok(hasher.result_str())
}

type Result<T> = std::result::Result<T, Error>;

#[derive(Debug)]
enum Error {
    Io(io::Error),
    Ignored(DirEntry),
    WalkDir(walkdir::Error),
}

fn process_root(root: &Path) -> io::Result<()> {
    let pb = root.to_path_buf();
    let producer_ctor = || WalkDir::new(pb);
    let xform_ctor = || {
        let mut hasher = Sha1::new();
        let mut buf = [0; 1024 * 8];
        let f = move |e: walkdir::Result<DirEntry>| -> Result<String> {
            let e = e.map_err(Error::WalkDir)?;
            if !e.file_type().is_file() {
                return Err(Error::Ignored(e));
            }
            calc_hash(e.path(), &mut hasher, &mut buf).map_err(Error::Io)
        };
        f
    };
    let results = scatter_gather(producer_ctor, xform_ctor);
    for r in results {
        println!("{:?}", r);
    }
    Ok(())
}

fn main() {
    let root = env::args().nth(1).unwrap_or(".".to_string());
    let root = Path::new(root.as_str());
    process_root(root).expect("Hello error 2!");
}
<|endoftext|>


<commit_before>mod app;
mod error;
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 anyhow::{anyhow, Context, Result};
use atty::Stream;
use globset::GlobBuilder;
use lscolors::LsColors;
use regex::bytes::{RegexBuilder, RegexSetBuilder};

use crate::error::print_error;
use crate::exec::CommandTemplate;
use crate::exit_codes::ExitCode;
use crate::filetypes::FileTypes;
#[cfg(unix)]
use crate::filter::OwnerFilter;
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 run() -> Result<ExitCode> {
    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_os("base-directory") {
        let base_directory = Path::new(base_directory);
        if !filesystem::is_dir(base_directory) {
            return Err(anyhow!(
                "The '--base-directory' path '{}' is not a directory.",
                base_directory.to_string_lossy()
            ));
        }
        env::set_current_dir(base_directory).with_context(|| {
            format!(
                "Could not set '{}' as the current working directory.",
                base_directory.to_string_lossy()
            )
        })?;
    }

    let current_directory = Path::new(".");
    if !filesystem::is_dir(current_directory) {
        return Err(anyhow!(
            "Could not retrieve current directory (has it been deleted?)."
        ));
    }

    // Get the search pattern
    let pattern = matches
        .value_of_os("pattern")
        .map(|p| {
            p.to_str()
                .ok_or_else(|| anyhow!("The search pattern includes invalid UTF-8 sequences."))
        })
        .transpose()?
        .unwrap_or("");

    // Get one or more root directories to search.
    let mut dir_vec: Vec<_> = match matches
        .values_of_os("path")
        .or_else(|| matches.values_of_os("search-path"))
    {
        Some(paths) => paths
            .map(|path| {
                let path_buffer = PathBuf::from(path);
                if filesystem::is_dir(&path_buffer) {
                    Ok(path_buffer)
                } else {
                    Err(anyhow!(
                        "Search path '{}' is not a directory.",
                        path_buffer.to_string_lossy()
                    ))
                }
            })
            .inspect(|res| {
                if let Err(e) = res {
                    print_error(format!("{}", e))
                }
            })
            .filter_map(Result::ok)
            .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))
    {
        return Err(anyhow!(
            "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 your pattern to match the full file path, use:\n\n  \
             fd --full-path '{pattern}'",
            pattern = pattern,
            sep = std::path::MAIN_SEPARATOR,
        ));
    }

    let pattern_regex = if matches.is_present("glob") && !pattern.is_empty() {
        let glob = GlobBuilder::new(pattern).literal_separator(true).build()?;
        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 interactive_terminal = atty::is(Stream::Stdout);
    let colored_output = match matches.value_of("color") {
        Some("always") => true,
        Some("never") => false,
        _ => env::var_os("NO_COLOR").is_none() && interactive_terminal,
    };

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

    #[cfg(windows)]
    ansi_term::enable_ansi_support().ok();

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

    let command = if let Some(args) = matches.values_of("exec") {
        Some(CommandTemplate::new(args))
    } else if let Some(args) = matches.values_of("exec-batch") {
        Some(CommandTemplate::new_batch(args)?)
    } else if matches.is_present("list-details") {
        let color = matches.value_of("color").unwrap_or("auto");
        let color_arg = ["--color=", color].concat();

        #[allow(unused)]
        let gnu_ls = |command_name| {
            vec![
                command_name,
                "-l",               // long listing format
                "--human-readable", // human readable file sizes
                "--directory",      // list directories themselves, not their contents
                &color_arg,
            ]
        };

        let cmd: Vec<&str> = if cfg!(unix) {
            if !cfg!(any(
                target_os = "macos",
                target_os = "dragonfly",
                target_os = "freebsd",
                target_os = "netbsd",
                target_os = "openbsd"
            )) {
                // Assume ls is GNU ls
                gnu_ls("ls")
            } else {
                // MacOS, DragonFlyBSD, FreeBSD
                use std::process::{Command, Stdio};

                // Use GNU ls, if available (support for --color=auto, better LS_COLORS support)
                let gnu_ls_exists = Command::new("gls")
                    .arg("--version")
                    .stdout(Stdio::null())
                    .stderr(Stdio::null())
                    .status()
                    .is_ok();

                if gnu_ls_exists {
                    gnu_ls("gls")
                } else {
                    let mut cmd = vec![
                        "ls", // BSD version of ls
                        "-l", // long listing format
                        "-h", // '--human-readable' is not available, '-h' is
                        "-d", // '--directory' is not available, but '-d' is
                    ];

                    if !cfg!(any(target_os = "netbsd", target_os = "openbsd")) && colored_output {
                        // -G is not available in NetBSD's and OpenBSD's ls
                        cmd.push("-G");
                    }

                    cmd
                }
            }
        } else if cfg!(windows) {
            use std::process::{Command, Stdio};

            // Use GNU ls, if available
            let gnu_ls_exists = Command::new("ls")
                .arg("--version")
                .stdout(Stdio::null())
                .stderr(Stdio::null())
                .status()
                .is_ok();

            if gnu_ls_exists {
                gnu_ls("ls")
            } else {
                return Err(anyhow!(
                    "'fd --list-details' is not supported on Windows unless GNU 'ls' is installed."
                ));
            }
        } else {
            return Err(anyhow!(
                "'fd --list-details' is not supported on this platform."
            ));
        };

        Some(CommandTemplate::new_batch(&cmd).unwrap())
    } else {
        None
    };

    let size_limits = if let Some(vs) = matches.values_of("size") {
        vs.map(|sf| {
            SizeFilter::from_string(sf)
                .ok_or_else(|| anyhow!("'{}' is not a valid size constraint. See 'fd --help'.", sf))
        })
        .collect::<Result<Vec<_>>>()?
    } 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 {
            return Err(anyhow!(
                "'{}' 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 {
            return Err(anyhow!(
                "'{}' is not a valid date or duration. See 'fd --help'.",
                t
            ));
        }
    }

    #[cfg(unix)]
    let owner_constraint = if let Some(s) = matches.value_of("owner") {
        OwnerFilter::from_string(s)?
    } else {
        None
    };

    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")),
        read_global_ignore: !(matches.is_present("no-ignore")
            || matches.is_present("rg-alias-hidden-ignore")
            || matches.is_present("no-global-ignore-file")),
        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("max-depth")
            .or_else(|| matches.value_of("rg-depth"))
            .or_else(|| matches.value_of("exact-depth"))
            .and_then(|n| usize::from_str_radix(n, 10).ok()),
        min_depth: matches
            .value_of("min-depth")
            .or_else(|| matches.value_of("exact-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,
        interactive_terminal,
        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,
                    "s" | "socket" => file_types.sockets = true,
                    "p" | "pipe" => file_types.pipes = 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)));
                RegexSetBuilder::new(patterns)
                    .case_insensitive(true)
                    .build()
            })
            .transpose()?,
        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,
        #[cfg(unix)]
        owner_constraint,
        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)
            .or_else(|| {
                if matches.is_present("max-one-result") {
                    Some(1)
                } else {
                    None
                }
            }),
    };

    let re = RegexBuilder::new(&pattern_regex)
        .case_insensitive(!config.case_sensitive)
        .dot_matches_new_line(true)
        .build()
        .map_err(|e| {
            anyhow!(
                "{}\n\nNote: You can use the '--fixed-strings' option to search for a \
                 literal string instead of a regular expression. Alternatively, you can \
                 also use the '--glob' option to match on a glob pattern.",
                e.to_string()
            )
        })?;

    walk::scan(&dir_vec, Arc::new(re), Arc::new(config))
}

fn main() {
    let result = run();
    match result {
        Ok(exit_code) => {
            process::exit(exit_code.into());
        }
        Err(err) => {
            eprintln!("[fd error]: {}", err);
            process::exit(ExitCode::GeneralError.into());
        }
    }
}
<commit_msg>Refactor to for-loop<commit_after>mod app;
mod error;
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 anyhow::{anyhow, Context, Result};
use atty::Stream;
use globset::GlobBuilder;
use lscolors::LsColors;
use regex::bytes::{RegexBuilder, RegexSetBuilder};

use crate::error::print_error;
use crate::exec::CommandTemplate;
use crate::exit_codes::ExitCode;
use crate::filetypes::FileTypes;
#[cfg(unix)]
use crate::filter::OwnerFilter;
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 run() -> Result<ExitCode> {
    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_os("base-directory") {
        let base_directory = Path::new(base_directory);
        if !filesystem::is_dir(base_directory) {
            return Err(anyhow!(
                "The '--base-directory' path '{}' is not a directory.",
                base_directory.to_string_lossy()
            ));
        }
        env::set_current_dir(base_directory).with_context(|| {
            format!(
                "Could not set '{}' as the current working directory.",
                base_directory.to_string_lossy()
            )
        })?;
    }

    let current_directory = Path::new(".");
    if !filesystem::is_dir(current_directory) {
        return Err(anyhow!(
            "Could not retrieve current directory (has it been deleted?)."
        ));
    }

    // Get the search pattern
    let pattern = matches
        .value_of_os("pattern")
        .map(|p| {
            p.to_str()
                .ok_or_else(|| anyhow!("The search pattern includes invalid UTF-8 sequences."))
        })
        .transpose()?
        .unwrap_or("");

    // Get one or more root directories to search.
    let passed_arguments = matches
        .values_of_os("path")
        .or_else(|| matches.values_of_os("search-path"));

    // Assign current directory to search vector.
    let mut dir_vec: Vec<_> = vec![current_directory.to_path_buf()];

    // Assign any valid arguments to search vector.
    if let Some(paths) = passed_arguments {
        dir_vec = vec![];
        for path in paths {
            let path_buffer = PathBuf::from(path);
            if filesystem::is_dir(&path_buffer) {
                dir_vec.push(path_buffer);
            }
            else {
                print_error(format!("Search path '{}' is not a directory.", path_buffer.to_string_lossy()));
            }
        }
    }

    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))
    {
        return Err(anyhow!(
            "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 your pattern to match the full file path, use:\n\n  \
             fd --full-path '{pattern}'",
            pattern = pattern,
            sep = std::path::MAIN_SEPARATOR,
        ));
    }

    let pattern_regex = if matches.is_present("glob") && !pattern.is_empty() {
        let glob = GlobBuilder::new(pattern).literal_separator(true).build()?;
        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 interactive_terminal = atty::is(Stream::Stdout);
    let colored_output = match matches.value_of("color") {
        Some("always") => true,
        Some("never") => false,
        _ => env::var_os("NO_COLOR").is_none() && interactive_terminal,
    };

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

    #[cfg(windows)]
    ansi_term::enable_ansi_support().ok();

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

    let command = if let Some(args) = matches.values_of("exec") {
        Some(CommandTemplate::new(args))
    } else if let Some(args) = matches.values_of("exec-batch") {
        Some(CommandTemplate::new_batch(args)?)
    } else if matches.is_present("list-details") {
        let color = matches.value_of("color").unwrap_or("auto");
        let color_arg = ["--color=", color].concat();

        #[allow(unused)]
        let gnu_ls = |command_name| {
            vec![
                command_name,
                "-l",               // long listing format
                "--human-readable", // human readable file sizes
                "--directory",      // list directories themselves, not their contents
                &color_arg,
            ]
        };

        let cmd: Vec<&str> = if cfg!(unix) {
            if !cfg!(any(
                target_os = "macos",
                target_os = "dragonfly",
                target_os = "freebsd",
                target_os = "netbsd",
                target_os = "openbsd"
            )) {
                // Assume ls is GNU ls
                gnu_ls("ls")
            } else {
                // MacOS, DragonFlyBSD, FreeBSD
                use std::process::{Command, Stdio};

                // Use GNU ls, if available (support for --color=auto, better LS_COLORS support)
                let gnu_ls_exists = Command::new("gls")
                    .arg("--version")
                    .stdout(Stdio::null())
                    .stderr(Stdio::null())
                    .status()
                    .is_ok();

                if gnu_ls_exists {
                    gnu_ls("gls")
                } else {
                    let mut cmd = vec![
                        "ls", // BSD version of ls
                        "-l", // long listing format
                        "-h", // '--human-readable' is not available, '-h' is
                        "-d", // '--directory' is not available, but '-d' is
                    ];

                    if !cfg!(any(target_os = "netbsd", target_os = "openbsd")) && colored_output {
                        // -G is not available in NetBSD's and OpenBSD's ls
                        cmd.push("-G");
                    }

                    cmd
                }
            }
        } else if cfg!(windows) {
            use std::process::{Command, Stdio};

            // Use GNU ls, if available
            let gnu_ls_exists = Command::new("ls")
                .arg("--version")
                .stdout(Stdio::null())
                .stderr(Stdio::null())
                .status()
                .is_ok();

            if gnu_ls_exists {
                gnu_ls("ls")
            } else {
                return Err(anyhow!(
                    "'fd --list-details' is not supported on Windows unless GNU 'ls' is installed."
                ));
            }
        } else {
            return Err(anyhow!(
                "'fd --list-details' is not supported on this platform."
            ));
        };

        Some(CommandTemplate::new_batch(&cmd).unwrap())
    } else {
        None
    };

    let size_limits = if let Some(vs) = matches.values_of("size") {
        vs.map(|sf| {
            SizeFilter::from_string(sf)
                .ok_or_else(|| anyhow!("'{}' is not a valid size constraint. See 'fd --help'.", sf))
        })
        .collect::<Result<Vec<_>>>()?
    } 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 {
            return Err(anyhow!(
                "'{}' 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 {
            return Err(anyhow!(
                "'{}' is not a valid date or duration. See 'fd --help'.",
                t
            ));
        }
    }

    #[cfg(unix)]
    let owner_constraint = if let Some(s) = matches.value_of("owner") {
        OwnerFilter::from_string(s)?
    } else {
        None
    };

    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")),
        read_global_ignore: !(matches.is_present("no-ignore")
            || matches.is_present("rg-alias-hidden-ignore")
            || matches.is_present("no-global-ignore-file")),
        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("max-depth")
            .or_else(|| matches.value_of("rg-depth"))
            .or_else(|| matches.value_of("exact-depth"))
            .and_then(|n| usize::from_str_radix(n, 10).ok()),
        min_depth: matches
            .value_of("min-depth")
            .or_else(|| matches.value_of("exact-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,
        interactive_terminal,
        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,
                    "s" | "socket" => file_types.sockets = true,
                    "p" | "pipe" => file_types.pipes = 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)));
                RegexSetBuilder::new(patterns)
                    .case_insensitive(true)
                    .build()
            })
            .transpose()?,
        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,
        #[cfg(unix)]
        owner_constraint,
        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)
            .or_else(|| {
                if matches.is_present("max-one-result") {
                    Some(1)
                } else {
                    None
                }
            }),
    };

    let re = RegexBuilder::new(&pattern_regex)
        .case_insensitive(!config.case_sensitive)
        .dot_matches_new_line(true)
        .build()
        .map_err(|e| {
            anyhow!(
                "{}\n\nNote: You can use the '--fixed-strings' option to search for a \
                 literal string instead of a regular expression. Alternatively, you can \
                 also use the '--glob' option to match on a glob pattern.",
                e.to_string()
            )
        })?;

    walk::scan(&dir_vec, Arc::new(re), Arc::new(config))
}

fn main() {
    let result = run();
    match result {
        Ok(exit_code) => {
            process::exit(exit_code.into());
        }
        Err(err) => {
            eprintln!("[fd error]: {}", err);
            process::exit(ExitCode::GeneralError.into());
        }
    }
}
<|endoftext|>


<commit_before>#[macro_use]
extern crate ecs;

use ecs::{World, BuildData, DataHelper, EntityIter, ModifyData, Process, System};
use ecs::system::{EntityProcess, EntitySystem};
use std::io;

#[derive(Copy, Clone, Debug, PartialEq)]
pub struct Location {
    pub row: i32,
    pub column: i32,
    pub occupant: char,
}

#[derive(Copy, Clone, Debug, PartialEq)]
pub struct Position {
    pub x: i32,
    pub y: i32,
}

#[derive(Copy, Clone, Debug, PartialEq)]
pub struct Velocity {
    pub dx: i32,
    pub dy: i32,
}

pub struct MotionProcess;

impl System for MotionProcess {
    type Components = WorldComponents;
    type Services = ();
}

impl EntityProcess for MotionProcess {
    fn process(&mut self,
               entities: EntityIter<WorldComponents>,
               data: &mut DataHelper<WorldComponents, ()>) {
        for e in entities {
            let mut position = data.position[e];
            let velocity = data.velocity[e];

            position.x += velocity.dx;
            position.y += velocity.dy;
            data.position[e] = position;
        }
    }
}

pub struct Command(pub String);

pub struct CommandProcess;

impl System for CommandProcess {
    type Components = WorldComponents;
    type Services = ();
}

impl EntityProcess for CommandProcess {
    fn process(&mut self,
               entities: EntityIter<WorldComponents>,
               data: &mut DataHelper<WorldComponents, ()>) {
        for e in entities {
        }
    }
}

pub struct RenderView;

impl System for RenderView {
    type Components = WorldComponents;
    type Services = ();
}

impl EntityProcess for RenderView {
    fn process(&mut self,
               entities: EntityIter<WorldComponents>,
               data: &mut DataHelper<WorldComponents, ()>) {
        let view = String::new();
        for e in entities {
        }
        //println!("{}", view);
    }
}

components! {
    struct WorldComponents {
        #[hot] command: Command,
        #[hot] position: Position,
        #[hot] velocity: Velocity,
        #[hot] location: Location,
    }
}

systems! {
    struct WorldSystems<WorldComponents, ()> {
        active: {
            motion: EntitySystem<MotionProcess> = EntitySystem::new(
                MotionProcess,
                aspect!(<WorldComponents> all: [position, velocity])
            ),
            render: EntitySystem<RenderView> = EntitySystem::new(
                RenderView,
                aspect!(<WorldComponents> all: [location])
            ),
        },
        passive: {}
    }
}

fn main() {
    let mut world = World::<WorldSystems>::new();
    let entity = world.create_entity(|entity: BuildData<WorldComponents>,
                                      data: &mut WorldComponents| {
        data.position.add(&entity, Position { x: 0, y: 0 });
        data.velocity.add(&entity, Velocity { dx: 0, dy: 0 });
    });
    let world_map = world.create_entity(|entity: BuildData<WorldComponents>,
                                      data: &mut WorldComponents| {
        data.location.add(&entity, Location { row: 0, column: 0, occupant: '🌲' });
        data.location.add(&entity, Location { row: 0, column: 1, occupant: '🌲' });
        data.location.add(&entity, Location { row: 0, column: 2, occupant: '🌲' });
        data.location.add(&entity, Location { row: 0, column: 3, occupant: '🌳' });
        data.location.add(&entity, Location { row: 0, column: 4, occupant: '🌲' });
        data.location.add(&entity, Location { row: 0, column: 5, occupant: '🌲' });
        data.location.add(&entity, Location { row: 0, column: 6, occupant: '🌲' });
        data.location.add(&entity, Location { row: 0, column: 7, occupant: '🌲' });
        data.location.add(&entity, Location { row: 0, column: 8, occupant: '🌲' });
        data.location.add(&entity, Location { row: 0, column: 9, occupant: '🌲' });
        data.location.add(&entity, Location { row: 1, column: 0, occupant: '🌲' });
        data.location.add(&entity, Location { row: 1, column: 1, occupant: '⬚' });
        data.location.add(&entity, Location { row: 1, column: 2, occupant: '⬚' });
        data.location.add(&entity, Location { row: 1, column: 3, occupant: '⬚' });
        data.location.add(&entity, Location { row: 1, column: 4, occupant: '⬚' });
        data.location.add(&entity, Location { row: 1, column: 5, occupant: '⬚' });
        data.location.add(&entity, Location { row: 1, column: 6, occupant: '⬚' });
        data.location.add(&entity, Location { row: 1, column: 7, occupant: '⬚' });
        data.location.add(&entity, Location { row: 1, column: 8, occupant: '⬚' });
        data.location.add(&entity, Location { row: 1, column: 9, occupant: '🌲' });
        data.location.add(&entity, Location { row: 2, column: 0, occupant: '🌲' });
        data.location.add(&entity, Location { row: 2, column: 1, occupant: '⬚' });
        data.location.add(&entity, Location { row: 2, column: 2, occupant: '⬚' });
        data.location.add(&entity, Location { row: 2, column: 3, occupant: '⬚' });
        data.location.add(&entity, Location { row: 2, column: 4, occupant: '⬚' });
        data.location.add(&entity, Location { row: 2, column: 5, occupant: '⬚' });
        data.location.add(&entity, Location { row: 2, column: 6, occupant: '⬚' });
        data.location.add(&entity, Location { row: 2, column: 7, occupant: '⬚' });
        data.location.add(&entity, Location { row: 2, column: 8, occupant: '⬚' });
        data.location.add(&entity, Location { row: 2, column: 9, occupant: '🌲' });
        data.location.add(&entity, Location { row: 3, column: 0, occupant: '🌲' });
        data.location.add(&entity, Location { row: 3, column: 1, occupant: '⬚' });
        data.location.add(&entity, Location { row: 3, column: 2, occupant: '⬚' });
        data.location.add(&entity, Location { row: 3, column: 3, occupant: '⬚' });
        data.location.add(&entity, Location { row: 3, column: 4, occupant: '⬚' });
        data.location.add(&entity, Location { row: 3, column: 5, occupant: '⬚' });
        data.location.add(&entity, Location { row: 3, column: 6, occupant: '⬚' });
        data.location.add(&entity, Location { row: 3, column: 7, occupant: '⬚' });
        data.location.add(&entity, Location { row: 3, column: 8, occupant: '⬚' });
        data.location.add(&entity, Location { row: 3, column: 9, occupant: '🌲' });
        data.location.add(&entity, Location { row: 4, column: 0, occupant: '🌲' });
        data.location.add(&entity, Location { row: 4, column: 1, occupant: '🌲' });
        data.location.add(&entity, Location { row: 4, column: 2, occupant: '🌲' });
        data.location.add(&entity, Location { row: 4, column: 3, occupant: '🌲' });
        data.location.add(&entity, Location { row: 4, column: 4, occupant: '🌲' });
        data.location.add(&entity, Location { row: 4, column: 5, occupant: '🌲' });
        data.location.add(&entity, Location { row: 4, column: 6, occupant: '🌲' });
        data.location.add(&entity, Location { row: 4, column: 7, occupant: '🌲' });
        data.location.add(&entity, Location { row: 4, column: 8, occupant: '🌲' });
        data.location.add(&entity, Location { row: 4, column: 9, occupant: '🌲' });
    });

    loop {
        let mut input = String::new();
        if let Ok(_) = io::stdin().read_line(&mut input) {
            world.update();
        }
    }
}
<commit_msg>Update render view working with basic map.<commit_after>#[macro_use]
extern crate ecs;

use ecs::{World, BuildData, DataHelper, EntityIter, ModifyData, Process, System};
use ecs::system::{EntityProcess, EntitySystem};
use std::io;

#[derive(Clone, Debug, PartialEq)]
pub struct WorldMap {
    pub width: usize,
    pub height: usize,
    pub map: Vec<char>,
}

#[derive(Copy, Clone, Debug, PartialEq)]
pub struct Position {
    pub x: i32,
    pub y: i32,
}

#[derive(Copy, Clone, Debug, PartialEq)]
pub struct Velocity {
    pub dx: i32,
    pub dy: i32,
}

pub struct MotionProcess;

impl System for MotionProcess {
    type Components = WorldComponents;
    type Services = ();
}

impl EntityProcess for MotionProcess {
    fn process(&mut self,
               entities: EntityIter<WorldComponents>,
               data: &mut DataHelper<WorldComponents, ()>) {
        for e in entities {
            let mut position = data.position[e];
            let velocity = data.velocity[e];

            position.x += velocity.dx;
            position.y += velocity.dy;
            data.position[e] = position;
        }
    }
}

pub struct CommandProcess(pub String);

impl System for CommandProcess {
    type Components = WorldComponents;
    type Services = ();
}

impl Process for CommandProcess {
    fn process(&mut self, _: &mut DataHelper<WorldComponents, ()>) {
        println!("{}", &self.0);
    }
}

pub struct RenderView;

impl System for RenderView {
    type Components = WorldComponents;
    type Services = ();
}

impl EntityProcess for RenderView {
    fn process(&mut self,
               entities: EntityIter<WorldComponents>,
               data: &mut DataHelper<WorldComponents, ()>) {
        for e in entities {
            let ref world_map = data.world_map[e];
            let height = world_map.height;
            let width = world_map.width;
            for i in 0..height {
                for j in 0..width {
                    print!("{}", world_map.map[i * width + j]);
                    if j == width - 1 {
                        println!("");
                    }
                }
            }
        }
    }
}

components! {
    struct WorldComponents {
        #[hot] position: Position,
        #[hot] velocity: Velocity,
        #[hot] world_map: WorldMap,
    }
}

systems! {
    struct WorldSystems<WorldComponents, ()> {
        active: {
            motion: EntitySystem<MotionProcess> = EntitySystem::new(
                MotionProcess,
                aspect!(<WorldComponents> all: [position, velocity])
            ),
            render: EntitySystem<RenderView> = EntitySystem::new(
                RenderView,
                aspect!(<WorldComponents> all: [world_map])
            ),
            command: CommandProcess = CommandProcess("idle".to_string()),
        },
        passive: {}
    }
}

fn main() {
    let mut world = World::<WorldSystems>::new();
    let entity = world.create_entity(|entity: BuildData<WorldComponents>,
                                      data: &mut WorldComponents| {
        data.position.add(&entity, Position { x: 0, y: 0 });
        data.velocity.add(&entity, Velocity { dx: 0, dy: 0 });
    });
    let world_map = world.create_entity(|entity: BuildData<WorldComponents>,
                                      data: &mut WorldComponents| {
        let map_matrix = vec![
            '🌲', '🌲', '🌲', '🌳', '🌲', '🌲', '🌲', '🌲', '🌲', '🌲',
            '🌲',  '⬚',  '⬚',  '⬚',  '⬚',  '⬚',  '⬚',  '⬚',  '⬚', '🌲',
            '🌲',  '⬚',  '⬚',  '⬚',  '⬚',  '⬚',  '⬚',  '⬚',  '⬚', '🌲',
            '🌲',  '⬚',  '⬚',  '⬚',  '⬚',  '⬚',  '⬚',  '⬚',  '⬚', '🌲',
            '🌲',  '⬚',  '⬚',  '⬚',  '⬚',  '⬚',  '⬚',  '⬚',  '⬚', '🌲',
            '🌲',  '⬚',  '⬚',  '⬚',  '⬚',  '⬚',  '⬚',  '⬚',  '⬚', '🌲',
            '🌲',  '⬚',  '⬚',  '⬚',  '⬚',  '⬚',  '⬚',  '⬚',  '⬚', '🌲',
            '🌲',  '⬚',  '⬚',  '⬚',  '⬚',  '⬚',  '⬚',  '⬚',  '⬚', '🌲',
            '🌲',  '⬚',  '⬚',  '⬚',  '⬚',  '⬚',  '⬚',  '⬚',  '⬚', '🌲',
            '🌲', '🌲', '🌲', '🌳', '🌲', '🌲', '🌲', '🌲', '🌲', '🌲'
        ];
        data.world_map.add(&entity, WorldMap { width: 10, height: 10, map: map_matrix });
    });

    loop {
        let mut input = String::new();
        if let Ok(_) = io::stdin().read_line(&mut input) {
            world.systems.command.0 = input;
            world.update();
        }
    }
}
<|endoftext|>


<commit_before>#[macro_use]
extern crate clap;

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

extern crate xmlrpc;
extern crate rustc_serialize;

extern crate regex;

use clap::{Arg, App};
use std::env;
use std::io;
use std::io::prelude::*;

use regex::Regex;

const GANDI_URL_PROD: &'static str = "https://rpc.gandi.net/xmlrpc/";

trait GandiAPI {
    fn init(&mut self, domain: &str);
    fn is_record_already_declared(&self, record_name: &str) -> Option<String>;
    fn update_record(&self, record_name: &str, ip_addr: &str);
    fn create_record(&self, record_name: &str, ip_addr: &str);
}

struct GandiAPIImpl<'a> {
  xmlrpc_server: &'a str,
  apikey: &'a str,
  zone_id: Option<u32>,
  zone_id_version: u16,
}

impl<'a> GandiAPIImpl<'a> {

    fn new(gandi_url: &'a str, gandi_apikey: &'a str) -> GandiAPIImpl<'a> {
        GandiAPIImpl {
            xmlrpc_server: gandi_url,
            apikey: gandi_apikey,
            zone_id: None,
            zone_id_version: 0,
        }
    }
}

impl<'a> GandiAPI for GandiAPIImpl<'a> {

    fn init(&mut self, domain: &str) {
        let client = xmlrpc::Client::new(self.xmlrpc_server);
        let mut request = xmlrpc::Request::new("domain.info");
        request = request.argument(&self.apikey.to_string());
        request = request.argument(&domain.to_string());
        request = request.finalize();

        let response = client.remote_call(&request).unwrap();

        // TODO: fix this ugly code
        // Handle errors
        let zone_id_pos = response.body.find("zone_id").unwrap();
        let (_, body_end) = response.body.split_at(zone_id_pos);
        let first_int_markup = body_end.find("<int>").unwrap();
        let (_, body_end) = body_end.split_at(first_int_markup + "<int>".len());
        let first_end_int_markup = body_end.find("</int>").unwrap();
        let (zone_id, _) = body_end.split_at(first_end_int_markup);
        self.zone_id = zone_id.parse::<u32>().ok();

        debug!("Zone id: {}", self.zone_id.unwrap());
    }

    fn is_record_already_declared(&self, record_name: &str) -> Option<String> {

        let response = &self.get_record_list(record_name, &self.zone_id_version);

        // Extract already configured IP address
        // We are looking for something like that: <value><string>55.32.210.10</string></value>
        let regex = Regex::new(r"<value><string>([0-9.]*)</string></value>").unwrap();

        let caps = regex.captures(&*response.body);

        caps
            .map_or(None, |caps| caps.at(1))
            .map(|val| val.to_string())
    }

    fn update_record(&self, record_name: &str, ip_addr: &str) {

        // Create a new zone and get return id
        let client = xmlrpc::Client::new(self.xmlrpc_server);
        let mut request = xmlrpc::Request::new("domain.zone.version.new");
        request = request.argument(&self.apikey.to_string());
        request = request.argument(&self.zone_id.unwrap());

        let response = client.remote_call(&request).unwrap();

        // Extract new zone version
        // We are looking for something like that: <int>5</int>
        let regex = Regex::new(r"<int>([0-9]+)</int>").unwrap();

        let caps = regex.captures(&*response.body).unwrap();

        let new_zone_id:u16 = caps.at(1).unwrap().parse::<u16>().ok().unwrap();

        debug!("New zone version: {}", new_zone_id);

        unimplemented!();
    }

    fn create_record(&self, record_name: &str, ip_addr: &str) {
        unimplemented!();
    }
}

impl<'a> GandiAPIImpl<'a> {

    fn get_record_list(&self, record_name: &str, zone_id_version: &u16) -> xmlrpc::Response {

        let client = xmlrpc::Client::new(self.xmlrpc_server);
        let mut request = xmlrpc::Request::new("domain.zone.record.list");
        request = request.argument(&self.apikey.to_string());
        request = request.argument(&self.zone_id.unwrap());
        request = request.argument(zone_id_version);

        #[derive(Debug,RustcEncodable,RustcDecodable)]
        struct Record {
            name: String,
            type_: String,
        }

        let record = Record { name: record_name.to_string(), type_: "A".to_string() };

        request = request.argument(&record);

        request = request.finalize();

        // Horrible hack, because 'type' is a reserved keyword ...
        request.body = request.body.replace("type_", "type");

        client.remote_call(&request).unwrap()
    }
}

fn main() {
    let matches = App::new("gdu")
        .version(&crate_version!()[..])
        .author("Damien Lecan <dev@dlecan.com>")
        .about("Gandi DNS updater, useful to reflect your dynamic IP address to your Gandi DNS zone file.\nIP address is read from stdin.")
        .args_from_usage(
            "-a --apikey=[apikey] 'Your API key provided by Gandi'
            -d --domain=[domain] 'The domain name whose active zonefile will be updated, e.g. \"domain.com\"'
            -n --dry-run 'Dry run, don't really update Gandi zone file'
            [verbose]... -v 'Verbose mode'")
        .arg(Arg::with_name("record_name")
            .help("Name of the A record to update or create (without domain)")
            .index(1)
            .required(true)
            .multiple(false))
        .get_matches();

    // Init logging to DEBUG only if user requires it
    match matches.occurrences_of("verbose") {
        0 => (),
        1 => {
                println!("Verbose mode");
                env::set_var("RUST_LOG", "DEBUG");
            },
        2 | _=> {
                println!("More verbose mode");
                env::set_var("RUST_LOG", "TRACE");
            }
    }
    env_logger::init().unwrap();

    let apikey = matches.value_of("apikey").unwrap();
    debug!("Using apikey: {}", apikey);

    let domain = matches.value_of("domain").unwrap();
    debug!("Using domain: {}", domain);

    let record_name = matches.value_of("record_name").unwrap();
    debug!("Using record name: {}", record_name);

    let dry_run = matches.is_present("dry-run");
    debug!("Dry run: {}", dry_run);

    let mut input = String::new();
    match io::stdin().read_line(&mut input) {
        Ok(_) => {
            println!("Input: {}", input);
        }
        Err(error) => println!("error: {}", error),
    }

    let detected_ip_addr = input.trim();

    let mut gandi_api = GandiAPIImpl::new(GANDI_URL_PROD, apikey);

    gandi_api.init(domain);

    let maybe_checked = gandi_api.is_record_already_declared(record_name);

    match maybe_checked {
        Some(ip_addr) => {
            debug!("Record already declared, with IP address: {}", &ip_addr);

            if &ip_addr == detected_ip_addr {
                debug!("IP address unmodified, no record to update");
            } else {
                debug!("Update record '{}' with IP address '{}'", record_name, &ip_addr);
                gandi_api.update_record(record_name, &ip_addr);
            }
        }
    //     None => gandi_api.createRecord(record_name, detectedIpAddr)
        None => ()
    }

}
<commit_msg>Full update process<commit_after>#[macro_use]
extern crate clap;

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

extern crate xmlrpc;
extern crate rustc_serialize;

extern crate regex;

use clap::{Arg, App};
use std::env;
use std::io;
use std::io::prelude::*;

use regex::Regex;

const GANDI_URL_PROD: &'static str = "https://rpc.gandi.net/xmlrpc/";

trait GandiAPI {
    fn init(&mut self, domain: &str);
    fn is_record_already_declared(&self, record_name: &str) -> Option<String>;
    fn update_record(&self, record_name: &str, ip_addr: &str) -> bool;
    fn create_record(&self, record_name: &str, ip_addr: &str);
}

struct GandiAPIImpl<'a> {
  xmlrpc_server: &'a str,
  apikey: &'a str,
  zone_id: Option<u32>,
  zone_id_version: u16,
}

impl<'a> GandiAPIImpl<'a> {

    fn new(gandi_url: &'a str, gandi_apikey: &'a str) -> GandiAPIImpl<'a> {
        GandiAPIImpl {
            xmlrpc_server: gandi_url,
            apikey: gandi_apikey,
            zone_id: None,
            zone_id_version: 0,
        }
    }
}

impl<'a> GandiAPI for GandiAPIImpl<'a> {

    fn init(&mut self, domain: &str) {

        let (client, mut request) = self.get_gandi_client("domain.info");
        request = request.argument(&domain.to_string());
        request = request.finalize();

        let response = client.remote_call(&request).unwrap();

        // TODO: fix this ugly code
        // Handle errors
        let zone_id_pos = response.body.find("zone_id").unwrap();
        let (_, body_end) = response.body.split_at(zone_id_pos);
        let first_int_markup = body_end.find("<int>").unwrap();
        let (_, body_end) = body_end.split_at(first_int_markup + "<int>".len());
        let first_end_int_markup = body_end.find("</int>").unwrap();
        let (zone_id, _) = body_end.split_at(first_end_int_markup);
        self.zone_id = zone_id.parse::<u32>().ok();

        debug!("Zone id: {}", self.zone_id.unwrap());
    }

    fn is_record_already_declared(&self, record_name: &str) -> Option<String> {

        let response = &self.get_record_list(record_name, &self.zone_id_version);

        // Extract already configured IP address
        // We are looking for something like that: <value><string>55.32.210.10</string></value>
        let regex = Regex::new(r"<value><string>([0-9.]*)</string></value>").unwrap();

        let caps = regex.captures(&*response.body);

        caps
            .map_or(None, |caps| caps.at(1))
            .map(|val| val.to_string())
    }

    fn update_record(&self, record_name: &str, ip_addr: &str) -> bool {

        // Create a new zone and get return version

        let (client, mut request) = self.get_gandi_client("domain.zone.version.new");
        request = request.argument(&self.zone_id.unwrap());
        request = request.finalize();

        let response = client.remote_call(&request).unwrap();

        let regex = Regex::new(r"<int>([0-9]+)</int>").unwrap();

        let caps = regex.captures(&*response.body).unwrap();

        let new_zone_version = caps.at(1).unwrap().parse::<u16>().ok().unwrap();

        debug!("New zone version: {}", new_zone_version);

        // Extract new record id

        let response = &self.get_record_list(record_name, &new_zone_version);

        let regex = Regex::new(r"<int>([0-9]+)</int>").unwrap();

        let caps = regex.captures(&*response.body).unwrap();

        let new_record_id = caps.at(1).unwrap().parse::<u32>().ok().unwrap();

        debug!("New record id: {}", new_record_id);

        // Update zone with the new record

        let (client, mut request) = self.get_gandi_client("domain.zone.record.update");
        request = request.argument(&self.zone_id.unwrap());
        request = request.argument(&new_zone_version);

        #[derive(Debug,RustcEncodable,RustcDecodable)]
        struct NewRecordId { id: u32 };
        request = request.argument(&NewRecordId{ id: new_record_id });

        #[derive(Debug,RustcEncodable,RustcDecodable)]
        struct Record {
            name: String,
            type_: String,
            value: String,
        }

        let record = Record {
            name: record_name.to_string(),
            type_: "A".to_string(),
            value: ip_addr.to_string(),
        };

        request = request.argument(&record);

        request = request.finalize();

        // Horrible hack, because 'type' is a reserved keyword ...
        request.body = request.body.replace("type_", "type");

        client.remote_call(&request); // ignore response

        // Activate the new zone
        debug!("Activate version '{}' of the zone '{}'", new_zone_version, &self.zone_id.unwrap());

        let (client, mut request) = self.get_gandi_client("domain.zone.version.set");
        request = request.argument(&self.zone_id.unwrap());
        request = request.argument(&new_zone_version);
        request = request.finalize();

        /*let response = */client.remote_call(&request);

        // let regex = Regex::new(r"<boolean>([0-1]+)</boolean>").unwrap();

        // let caps = regex.captures(&*response.body).unwrap();

        // let result = caps.at(1).unwrap();

        // debug!("Activate version result: {}", result);

        // match result {
        //     "1" => true,
        //     "0" | _ => false,
        // }
        true
    }

    fn create_record(&self, record_name: &str, ip_addr: &str) {
        unimplemented!();
    }
}

impl<'a> GandiAPIImpl<'a> {

    fn get_gandi_client(&self, rpc_action: &str) -> (xmlrpc::Client, xmlrpc::Request) {
        let client = xmlrpc::Client::new(self.xmlrpc_server);
        let mut request = xmlrpc::Request::new(rpc_action);
        request = request.argument(&self.apikey.to_string());
        (client, request)
    }

    fn get_record_list(&self, record_name: &str, zone_id_version: &u16) -> xmlrpc::Response {

        let (client, mut request) = self.get_gandi_client("domain.zone.record.list");
        request = request.argument(&self.zone_id.unwrap());
        request = request.argument(zone_id_version);

        #[derive(Debug,RustcEncodable,RustcDecodable)]
        struct Record {
            name: String,
            type_: String,
        }

        let record = Record { name: record_name.to_string(), type_: "A".to_string() };

        request = request.argument(&record);

        request = request.finalize();

        // Horrible hack, because 'type' is a reserved keyword ...
        request.body = request.body.replace("type_", "type");

        client.remote_call(&request).unwrap()
    }
}

fn main() {
    let matches = App::new("gdu")
        .version(&crate_version!()[..])
        .author("Damien Lecan <dev@dlecan.com>")
        .about("Gandi DNS updater, useful to reflect your dynamic IP address to your Gandi DNS zone file.\nIP address is read from stdin.")
        .args_from_usage(
            "-a --apikey=[apikey] 'Your API key provided by Gandi'
            -d --domain=[domain] 'The domain name whose active zonefile will be updated, e.g. \"domain.com\"'
            -n --dry-run 'Dry run, don't really update Gandi zone file'
            -f --force 'Force new zonefile creation even if IP address isn\'t modified'
            [verbose]... -v 'Verbose mode'")
        .arg(Arg::with_name("record_name")
            .help("Name of the A record to update or create (without domain)")
            .index(1)
            .required(true)
            .multiple(false))
        .get_matches();

    // Init logging to DEBUG only if user requires it
    match matches.occurrences_of("verbose") {
        0 => (),
        1 => {
                println!("Verbose mode");
                env::set_var("RUST_LOG", "DEBUG");
            },
        2 | _=> {
                println!("More verbose mode");
                env::set_var("RUST_LOG", "TRACE");
            }
    }
    env_logger::init().unwrap();

    let apikey = matches.value_of("apikey").unwrap();
    debug!("Using apikey: {}", apikey);

    let domain = matches.value_of("domain").unwrap();
    debug!("Using domain: {}", domain);

    let record_name = matches.value_of("record_name").unwrap();
    debug!("Using record name: {}", record_name);

    let dry_run = matches.is_present("dry-run");
    debug!("Dry run: {}", dry_run);

    let force = matches.is_present("force");
    debug!("Force: {}", force);

    let mut input = String::new();
    match io::stdin().read_line(&mut input) {
        Ok(_) => {
            println!("Input: {}", input);
        }
        Err(error) => println!("error: {}", error),
    }

    let detected_ip_addr = input.trim();

    let mut gandi_api = GandiAPIImpl::new(GANDI_URL_PROD, apikey);

    gandi_api.init(domain);

    let maybe_checked = gandi_api.is_record_already_declared(record_name);

    match maybe_checked {
        Some(ip_addr) => {
            debug!("Record already declared, with IP address: {}", &ip_addr);

            if !force && (&ip_addr == detected_ip_addr) {
                debug!("IP address not modified, no record to update");
            } else {
                debug!("Update record '{}' with IP address '{}'", record_name, &ip_addr);
                let result = gandi_api.update_record(record_name, &ip_addr);
                debug!("End of update process with result: {}", result);
            }
        }
    //     None => gandi_api.createRecord(record_name, detectedIpAddr)
        None => ()
    }

}
<|endoftext|>


<commit_before>extern crate termion;

fn main() {
    print!("{}{}Stuff\n", termion::clear::All, termion::cursor::Goto(1, 1));
}
<commit_msg>Write something that actually works<commit_after>extern crate termion;

use termion::event::{Event, Key};
use termion::raw::IntoRawMode;
use termion::input::TermRead;
use std::io::{Write, stdin, stdout};

fn main() {
    let stdin = stdin();
    let mut stdout = stdout().into_raw_mode().unwrap();
    write!(stdout, "{}{}Press Ctrl-Q to quit", termion::clear::All, termion::cursor::Goto(1, 1)).unwrap();
    stdout.flush().unwrap();
    for c in stdin.events() {
        let evt = c.unwrap();
        match evt {
            Event::Key(Key::Ctrl('q')) => break,
            _ => {}
        }
        stdout.flush().unwrap();
    }
    write!(stdout, "{}{}", termion::clear::All, termion::cursor::Goto(1, 1)).unwrap();
}
<|endoftext|>


<commit_before>#[macro_use]
extern crate log;
#[cfg(feature = "env_logger")]
extern crate env_logger;
#[macro_use]
extern crate clap;
extern crate futures;

extern crate gluon_base as base;
extern crate gluon;
extern crate gluon_check as check;
extern crate gluon_parser as parser;
#[macro_use]
extern crate gluon_vm as vm;

#[cfg(not(test))]
use gluon::{new_vm, Compiler, Thread, Error, Result};
#[cfg(not(test))]
use gluon::vm::thread::ThreadInternal;
#[cfg(not(test))]
use gluon::vm::Error as VMError;

mod repl;

#[cfg(not(test))]
fn run_files<'s, I>(vm: &Thread, files: I) -> Result<()>
    where I: Iterator<Item = &'s str>,
{
    let mut compiler = Compiler::new();
    for file in files {
        compiler.load_file(&vm, file)?;
    }
    Ok(())
}

#[cfg(all(not(test), feature = "env_logger"))]
fn init_env_logger() {
    ::env_logger::init().unwrap();
}

#[cfg(all(not(test), not(feature = "env_logger")))]
fn init_env_logger() {}

#[cfg(not(test))]
fn main() {
    const GLUON_VERSION: &'static str = env!("CARGO_PKG_VERSION");

    // Need the extra stack size when compiling the program using the msvc compiler
    ::std::thread::Builder::new()
        .stack_size(2 * 1024 * 1024)
        .spawn(|| {
            init_env_logger();

            let matches = clap_app!(gluon =>
                (version: GLUON_VERSION)
                (about: "executes gluon programs")
                (@arg REPL: -i --interactive "Starts the repl")
                (@arg INPUT: ... "Executes each file as a gluon program")
            )
                .get_matches();
            if matches.is_present("REPL") {
                if let Err(err) = repl::run() {
                    println!("{}", err);
                }
            } else if let Some(args) = matches.values_of("INPUT") {
                let vm = new_vm();
                match run_files(&vm, args) {
                    Ok(()) => (),
                    Err(err @ Error::VM(VMError::Message(_))) => {
                        println!("{}\n{}", err, vm.context().stack.stacktrace(0));
                    }
                    Err(msg) => println!("{}", msg),
                }
            } else {
                println!("{}", matches.usage());
            }
        })
        .unwrap()
        .join()
        .unwrap();
}
<commit_msg>test: Add a test which suppresses the unused imports warnings in src/main.rs<commit_after>#[macro_use]
extern crate log;
#[cfg(feature = "env_logger")]
extern crate env_logger;
#[macro_use]
extern crate clap;
extern crate futures;

extern crate gluon_base as base;
extern crate gluon;
extern crate gluon_check as check;
extern crate gluon_parser as parser;
#[macro_use]
extern crate gluon_vm as vm;

use gluon::{new_vm, Compiler, Thread, Error, Result};
use gluon::vm::thread::ThreadInternal;
use gluon::vm::Error as VMError;

mod repl;

fn run_files<'s, I>(vm: &Thread, files: I) -> Result<()>
    where I: Iterator<Item = &'s str>,
{
    let mut compiler = Compiler::new();
    for file in files {
        compiler.load_file(&vm, file)?;
    }
    Ok(())
}

#[cfg(feature = "env_logger")]
fn init_env_logger() {
    let _ = ::env_logger::init();
}

#[cfg(not(feature = "env_logger"))]
fn init_env_logger() {}

fn main() {
    const GLUON_VERSION: &'static str = env!("CARGO_PKG_VERSION");

    // Need the extra stack size when compiling the program using the msvc compiler
    ::std::thread::Builder::new()
        .stack_size(2 * 1024 * 1024)
        .spawn(|| {
            init_env_logger();

            let matches = clap_app!(gluon =>
                (version: GLUON_VERSION)
                (about: "executes gluon programs")
                (@arg REPL: -i --interactive "Starts the repl")
                (@arg INPUT: ... "Executes each file as a gluon program")
            )
                .get_matches();
            if matches.is_present("REPL") {
                if let Err(err) = repl::run() {
                    println!("{}", err);
                }
            } else if let Some(args) = matches.values_of("INPUT") {
                let vm = new_vm();
                match run_files(&vm, args) {
                    Ok(()) => (),
                    Err(err @ Error::VM(VMError::Message(_))) => {
                        println!("{}\n{}", err, vm.context().stack.stacktrace(0));
                    }
                    Err(msg) => println!("{}", msg),
                }
            } else {
                println!("{}", matches.usage());
            }
        })
        .unwrap()
        .join()
        .unwrap();
}

#[cfg(test)]
mod tests {
    // If nothing else this suppresses the unused imports warnings when compiling in test mode
    #[test]
    fn execute_repl_help() {
        super::main();
    }
}
<|endoftext|>


<commit_before>extern crate iron;
#[macro_use]
extern crate router;
extern crate serde_json;
extern crate sbb_telegram_bot;
extern crate reqwest;
extern crate dotenv;
#[macro_use]
extern crate maplit;

use dotenv::dotenv;
use std::env;

use iron::prelude::*;
use iron::status;
use iron::{Iron, Request, Response, IronResult, AfterMiddleware, Chain};
use router::NoRoute;
use std::io::Read;
use sbb_telegram_bot::model::telegram;
struct Custom404;

impl AfterMiddleware for Custom404 {
    fn catch(&self, req: &mut Request, err: IronError) -> IronResult<Response> {
        if let Some(_) = err.error.downcast::<NoRoute>() {
            Ok(Response::with((status::NotFound, format!("Invalid request: {}", req.url))))
        } else {
            Err(err)
        }
    }
}

fn main() {
    dotenv().ok();
    let router = router!(telegram: post "/sbb/telegram" => telegram);
    let mut chain = Chain::new(router);
    chain.link_after(Custom404);
    Iron::new(chain).http("localhost:3001").unwrap();

    fn telegram(req: &mut Request) -> IronResult<Response> {
        let mut body = Vec::new();
        req.body
            .read_to_end(&mut body)
            .map_err(|e|
                IronError::new(e,
                    (status::InternalServerError, "Error reading request")
                )
            )?;
        let body = String::from_utf8(body).unwrap();
        let update: telegram::Update = serde_json::from_str(&body).unwrap();
        if let Some(msg) = update.message {
            if let Some(txt) = msg.text {
                if txt == "/start" {
                    let url = format!("{}{}{}",
                                      "https://api.telegram.org/bot",
                                      bot_token(),
                                      "/sendMessage");
                    let params = hashmap![
                        "chat_id" => format!("{}", msg.chat.id),
                        "text" => "If the bot was already working, \
                                    you would now have registered yourself. \
                                    Alas, as this is only a placeholder text, \
                                    nothing happened".to_owned(),
                    ];
                    let client = reqwest::Client::new().unwrap();
                    client.post(&url)
                        .json(&params)
                        .send()
                        .unwrap();
                }
            }
        }
        Ok(Response::with((status::Ok, "ok")))
    }
}

fn bot_token() -> String {
    env::var_os("TELEGRAM_BOT_TOKEN")
        .expect("TELEGRAM_BOT_TOKEN must be specified. \
                Did you forget to add it to your .env file?")
        .into_string()
        .expect("TELEGRAM_BOT_TOKEN does not contain a valid UTF8 string")
}
<commit_msg>Improve Performance<commit_after>extern crate iron;
#[macro_use]
extern crate router;
extern crate serde_json;
extern crate sbb_telegram_bot;
extern crate reqwest;
extern crate dotenv;
#[macro_use]
extern crate maplit;

use dotenv::dotenv;
use std::env;

use iron::prelude::*;
use iron::status;
use iron::{Iron, Request, Response, IronResult, AfterMiddleware, Chain};
use router::NoRoute;
use std::io::Read;
use sbb_telegram_bot::model::telegram;
struct Custom404;

impl AfterMiddleware for Custom404 {
    fn catch(&self, req: &mut Request, err: IronError) -> IronResult<Response> {
        if let Some(_) = err.error.downcast::<NoRoute>() {
            Ok(Response::with((status::NotFound, format!("Invalid request: {}", req.url))))
        } else {
            Err(err)
        }
    }
}

fn main() {
    dotenv().ok();
    let router = router!(telegram: post "/sbb/telegram" => telegram);
    let mut chain = Chain::new(router);
    chain.link_after(Custom404);
    Iron::new(chain).http("localhost:3001").unwrap();

    fn telegram(req: &mut Request) -> IronResult<Response> {
        let mut body = String::new();
        req.body
            .read_to_string(&mut body)
            .map_err(|e| IronError::new(e, (status::BadRequest, "Error reading request")))?;
        let update: telegram::Update = serde_json::from_str(&body).unwrap();
        if let Some(msg) = update.message {
            if let Some(txt) = msg.text {
                if txt == "/start" {
                    let url = format!("{}{}{}",
                                      "https://api.telegram.org/bot",
                                      bot_token(),
                                      "/sendMessage");
                    let params = hashmap![
                        "chat_id" => format!("{}", msg.chat.id),
                        "text" => "If the bot was already working, \
                                    you would now have registered yourself. \
                                    Alas, as this is only a placeholder text, \
                                    nothing happened".to_owned(),
                    ];
                    let client = reqwest::Client::new().map_err(|e| {
                                     IronError::new(e,
                                                    (status::BadRequest, "Error reading request"))
                                 })?;
                    client.post(&url)
                        .json(&params)
                        .send()
                        .unwrap();
                }
            }
        }
        Ok(Response::with((status::Ok, "ok")))
    }
}

fn bot_token() -> String {
    env::var_os("TELEGRAM_BOT_TOKEN")
        .expect("TELEGRAM_BOT_TOKEN must be specified. \
                Did you forget to add it to your .env file?")
        .into_string()
        .expect("TELEGRAM_BOT_TOKEN does not contain a valid UTF8 string")
}
<|endoftext|>


<commit_before>#![allow(unused_must_use)]
#![allow(dead_code)]

mod tmi;
mod demc;
mod keystroke;

extern crate regex;
extern crate toml;
extern crate time;

use std::fs::File;
use std::fs::OpenOptions;
use std::io::Read;
use std::io::Write;
use std::path::Path;

use demc::{DemC, ChatInterfaced};
use demc::vgcnc::{VGcnC, sample_gcn_controller_hardware};

const CONFIG_FILE_PATH: &'static str = "tppm.toml";
const CHAT_LOG_PATH: &'static str = "chat.txt";
const VJOY_DEVICE_NUMBER: u32 = 1;
const ACCEPT_CONTROLLER_COMMANDS_ON_BOOT: bool = true;

enum ModCommand {
    SaveState,
    LoadState,
    UnplugController,
    PlugController
}
fn parse_mod_commands(sender: &String, msg: &String) -> Option<ModCommand> {
    match sender.to_lowercase().as_ref() {
        "twitchplayspapermario"|"xxn1"|"kalarmar" => {
            match msg.to_lowercase().as_ref() {
                "!savestate" => Some(ModCommand::SaveState),
                "!loadstate" => Some(ModCommand::LoadState),
                "!unplugcontroller" => Some(ModCommand::UnplugController),
                "!plugcontroller" => Some(ModCommand::PlugController),
                _ => None
            }
        },
        _ => None
    }
}

enum ChatMessageHandler {
    ModCommandHandler,
    ControllerCommandHandler,
}
fn log_tmi_message(sender: &String, message: &String, handler: &Option<ChatMessageHandler>, log: &mut File) {
    let log_string = match handler {
        &Some(ref handler) => match handler {
            &ChatMessageHandler::ModCommandHandler => format!("!{}: {}", sender, message),
            &ChatMessageHandler::ControllerCommandHandler => format!("_{}: {}", sender, message),
        },
        &None => format!("{}: {}", sender, message)
    };

    log.write_all(&log_string.as_bytes());
    log.write_all("\r\n".as_bytes());
    log.flush();
    println!("{}", log_string);
}

fn handle_tmi_message<T>(sender: &String, message: &String, accepting_controller_commands: bool,
                         controller: &DemC<T>, log: &mut File) -> Option<bool>
{
    let mut message_handler = None;
    let mut new_accept_controller_command_value = None;

    if !message_handler.is_some() {
        match parse_mod_commands(sender, message) {
            Some(mod_command) => {
                match mod_command {
                    ModCommand::SaveState => {
                        keystroke::send_combo(&[keystroke::Key::Physical(keystroke::Physical::Shift), keystroke::Key::Physical(keystroke::Physical::F1)]);
                    },
                    ModCommand::LoadState => {
                        keystroke::press_key(keystroke::Key::Physical(keystroke::Physical::F1));
                    },
                    ModCommand::UnplugController => {
                        new_accept_controller_command_value = Some(false);
                    },
                    ModCommand::PlugController => {
                        new_accept_controller_command_value = Some(true);
                    }
                }
                message_handler = Some(ChatMessageHandler::ModCommandHandler);
            },
            None => ()
        }
    }

    if !message_handler.is_some() {
        match accepting_controller_commands {
            true => match controller.handle_commands(message) {
                Ok(_) => {
                    message_handler = Some(ChatMessageHandler::ControllerCommandHandler);
                },
                Err(_) => ()
            },
            false => ()
        };
    }

    log_tmi_message(sender, message, &message_handler, log);

    new_accept_controller_command_value
}

fn main() {
    let (axes, joysticks, buttons) = sample_gcn_controller_hardware(VJOY_DEVICE_NUMBER).unwrap();
    let raw_controller = match VGcnC::new(VJOY_DEVICE_NUMBER, axes, joysticks, buttons) {
        Ok(controller) => controller,
        Err(err) => panic!("Unable to make raw controller: err {}", err)
    };

    // Initialize a democratized virtual controller
    let controller = match DemC::new(raw_controller, demc::ControllerConstraints {
        illegal_combinations: vec![
                                (String::from("start"), vec!(String::from("b"), String::from("x"))),
                                (String::from("b"), vec!(String::from("start"), String::from("x"))),
                                (String::from("x"), vec!(String::from("b"), String::from("start")))] } )
    {
        Ok(controller) => controller,
        Err(err) => panic!("Unable to create democratized controller: DemC error {}", err)
    };

    // Start our IRC connection
    let tmi_stream = match tmi::TmiStream::establish(CONFIG_FILE_PATH) {
        Ok(stream) => stream,
        Err(err) => panic!("Unable to establish TMI stream: TMI error {}", err)
    };

    let chat_log_path = Path::new(CHAT_LOG_PATH);
    let mut chat_log_file = match OpenOptions::new().read(true).write(true).append(true).create(true).
                                  open(&chat_log_path)
    {
        Ok(file) => file,
        Err(reason) => panic!("Couldn't open chat log file for writing! {}", std::error::Error::description(&reason))
    };

    let mut accepting_controller_commands = ACCEPT_CONTROLLER_COMMANDS_ON_BOOT;

    // Poll the IRC connection and handle its messages forever
    loop {
        match tmi_stream.receive() {
            Ok((sender, message)) => {
                match handle_tmi_message(&sender, &message, accepting_controller_commands, &controller, &mut chat_log_file) {
                    Some(val) => { accepting_controller_commands = val; },
                    None => ()
                }
            },
            Err(_) => ()
        }
    }
}
<commit_msg>Add a couple of mods<commit_after>#![allow(unused_must_use)]
#![allow(dead_code)]

mod tmi;
mod demc;
mod keystroke;

extern crate regex;
extern crate toml;
extern crate time;

use std::fs::File;
use std::fs::OpenOptions;
use std::io::Read;
use std::io::Write;
use std::path::Path;

use demc::{DemC, ChatInterfaced};
use demc::vgcnc::{VGcnC, sample_gcn_controller_hardware};

const CONFIG_FILE_PATH: &'static str = "tppm.toml";
const CHAT_LOG_PATH: &'static str = "chat.txt";
const VJOY_DEVICE_NUMBER: u32 = 1;
const ACCEPT_CONTROLLER_COMMANDS_ON_BOOT: bool = true;

enum ModCommand {
    SaveState,
    LoadState,
    UnplugController,
    PlugController
}
fn parse_mod_commands(sender: &String, msg: &String) -> Option<ModCommand> {
    match sender.to_lowercase().as_ref() {
        "twitchplayspapermario"|"xxn1"|"kalarmar"|"rashama_izouki"|"mooismyusername" => {
            match msg.to_lowercase().as_ref() {
                "!savestate" => Some(ModCommand::SaveState),
                "!loadstate" => Some(ModCommand::LoadState),
                "!unplugcontroller" => Some(ModCommand::UnplugController),
                "!plugcontroller" => Some(ModCommand::PlugController),
                _ => None
            }
        },
        _ => None
    }
}

enum ChatMessageHandler {
    ModCommandHandler,
    ControllerCommandHandler,
}
fn log_tmi_message(sender: &String, message: &String, handler: &Option<ChatMessageHandler>, log: &mut File) {
    let log_string = match handler {
        &Some(ref handler) => match handler {
            &ChatMessageHandler::ModCommandHandler => format!("!{}: {}", sender, message),
            &ChatMessageHandler::ControllerCommandHandler => format!("_{}: {}", sender, message),
        },
        &None => format!("{}: {}", sender, message)
    };

    log.write_all(&log_string.as_bytes());
    log.write_all("\r\n".as_bytes());
    log.flush();
    println!("{}", log_string);
}

fn handle_tmi_message<T>(sender: &String, message: &String, accepting_controller_commands: bool,
                         controller: &DemC<T>, log: &mut File) -> Option<bool>
{
    let mut message_handler = None;
    let mut new_accept_controller_command_value = None;

    if !message_handler.is_some() {
        match parse_mod_commands(sender, message) {
            Some(mod_command) => {
                match mod_command {
                    ModCommand::SaveState => {
                        keystroke::send_combo(&[keystroke::Key::Physical(keystroke::Physical::Shift), keystroke::Key::Physical(keystroke::Physical::F1)]);
                    },
                    ModCommand::LoadState => {
                        keystroke::press_key(keystroke::Key::Physical(keystroke::Physical::F1));
                    },
                    ModCommand::UnplugController => {
                        new_accept_controller_command_value = Some(false);
                    },
                    ModCommand::PlugController => {
                        new_accept_controller_command_value = Some(true);
                    }
                }
                message_handler = Some(ChatMessageHandler::ModCommandHandler);
            },
            None => ()
        }
    }

    if !message_handler.is_some() {
        match accepting_controller_commands {
            true => match controller.handle_commands(message) {
                Ok(_) => {
                    message_handler = Some(ChatMessageHandler::ControllerCommandHandler);
                },
                Err(_) => ()
            },
            false => ()
        };
    }

    log_tmi_message(sender, message, &message_handler, log);

    new_accept_controller_command_value
}

fn main() {
    let (axes, joysticks, buttons) = sample_gcn_controller_hardware(VJOY_DEVICE_NUMBER).unwrap();
    let raw_controller = match VGcnC::new(VJOY_DEVICE_NUMBER, axes, joysticks, buttons) {
        Ok(controller) => controller,
        Err(err) => panic!("Unable to make raw controller: err {}", err)
    };

    // Initialize a democratized virtual controller
    let controller = match DemC::new(raw_controller, demc::ControllerConstraints {
        illegal_combinations: vec![
                                (String::from("start"), vec!(String::from("b"), String::from("x"))),
                                (String::from("b"), vec!(String::from("start"), String::from("x"))),
                                (String::from("x"), vec!(String::from("b"), String::from("start")))] } )
    {
        Ok(controller) => controller,
        Err(err) => panic!("Unable to create democratized controller: DemC error {}", err)
    };

    // Start our IRC connection
    let tmi_stream = match tmi::TmiStream::establish(CONFIG_FILE_PATH) {
        Ok(stream) => stream,
        Err(err) => panic!("Unable to establish TMI stream: TMI error {}", err)
    };

    let chat_log_path = Path::new(CHAT_LOG_PATH);
    let mut chat_log_file = match OpenOptions::new().read(true).write(true).append(true).create(true).
                                  open(&chat_log_path)
    {
        Ok(file) => file,
        Err(reason) => panic!("Couldn't open chat log file for writing! {}", std::error::Error::description(&reason))
    };

    let mut accepting_controller_commands = ACCEPT_CONTROLLER_COMMANDS_ON_BOOT;

    // Poll the IRC connection and handle its messages forever
    loop {
        match tmi_stream.receive() {
            Ok((sender, message)) => {
                match handle_tmi_message(&sender, &message, accepting_controller_commands, &controller, &mut chat_log_file) {
                    Some(val) => { accepting_controller_commands = val; },
                    None => ()
                }
            },
            Err(_) => ()
        }
    }
}
<|endoftext|>


<commit_before>use std::io;
use std::io::prelude::*;

fn main() {
	let lockedStdin = io::stdin().lock();
	let byteLines : Vec<u8> = Vec::new();
	let lines : Vec<String> = Vec::new();

	match lockedStdin.read_to_end(byteLines) {
		Ok(a) => println!("stdin has length: {}", a),
		_ => println!("Error!")
	}

	for byteLine in byteLines.iter() {
		lines.push(String::from_utf8(byteLine).unwrap());
	}

	for line in lines.iter() {
		println!("{}", line);
	}
}<commit_msg>added more<commit_after>use std::io;
use std::io::prelude::*;

fn main() {
	let stdin = io::stdin();
	let mut locked = stdin.lock();

	let mut all_lines : String = String::new();

	println!("a");
	let stdin_bytes_count = locked.bytes().count();
	println!("{}", stdin_bytes_count);

	match locked.read_to_string(&mut all_lines) {
		Ok(a) => println!("stdin has length: {}", a),
		_ => println!("Error!")
	};
	println!("b");

	let lines : Vec<&str> = all_lines.split("\n").collect();

	for line in lines {
		println!("{}", line);
	}
}<|endoftext|>


<commit_before>#[macro_use]
extern crate serde_derive;

extern crate serde;
extern crate serde_json;

//TODO not hardcoded path
const KITAMAN_HOME : &str = "/home/kirillvr/.kitaman/";

#[derive(Serialize)]
enum Requirement {
    Binary(&'static str)
}

#[derive(Serialize)]
struct Requirements{
    requirements: Vec<Requirement>
}

impl Requirements {
    pub fn new() -> Requirements {
        Requirements{requirements: Vec::new()}
    }
    pub fn add(&mut self, requirement: Requirement) {
        self.requirements.push(requirement)
    }
}

fn main() {
   let mut requirements = Requirements::new();
   requirements.add(Requirement::Binary("ruby"))
}
<commit_msg>cargo fmt<commit_after>#[macro_use]
extern crate serde_derive;

extern crate serde;
extern crate serde_json;

//TODO not hardcoded path
const KITAMAN_HOME: &str = "/home/kirillvr/.kitaman/";

#[derive(Serialize)]
enum Requirement {
    Binary(&'static str),
}

#[derive(Serialize)]
struct Requirements {
    requirements: Vec<Requirement>,
}

impl Requirements {
    pub fn new() -> Requirements {
        Requirements {
            requirements: Vec::new(),
        }
    }
    pub fn add(&mut self, requirement: Requirement) {
        self.requirements.push(requirement)
    }
}

fn main() {
    let mut requirements = Requirements::new();
    requirements.add(Requirement::Binary("ruby"));
}
<|endoftext|>


<commit_before>#![crate_name = "clog"]
#![feature(plugin)]
#![plugin(regex_macros)]

extern crate regex;
extern crate time;

extern crate clap;

use git::LogReaderConfig;
use log_writer::{ LogWriter, LogWriterOptions };
use std::fs::File;
use std::io::Read;
use std::path::Path;
use std::borrow::ToOwned;

use clap::{App, Arg};

mod common;
mod git;
mod log_writer;
mod section_builder;
mod format_util;

fn main () {
    // Pull version from Cargo.toml
    let version = format!("{}.{}.{}{}",
                          env!("CARGO_PKG_VERSION_MAJOR"),
                          env!("CARGO_PKG_VERSION_MINOR"),
                          env!("CARGO_PKG_VERSION_PATCH"),
                          option_env!("CARGO_PKG_VERSION_PRE").unwrap_or(""));
    let matches = App::new("clog")
        .version(&version[..])
        .about("a conventional changelog for the rest of us")
        .arg(Arg::new("repository")
            .short("r")
            .long("repository")
            .takes_value(true)
            .required(true)
            .help("e.g. https://github.com/thoughtram/clog"))
        .arg(Arg::new("setversion")
            .long("setversion")
            .help("e.g. 1.0.1")
            .takes_value(true))
        .arg(Arg::new("subtitle")
            .long("subtitle")
            .help("e.g. crazy-release-title")
            .takes_value(true)
            .required(true))
        .arg(Arg::new("from")
            .help("e.g. 12a8546")
            .long("from")
            .takes_value(true))
        .arg(Arg::new("to")
            .long("to")
            .help("e.g. 8057684")
            .takes_value(true))
        .arg(Arg::new("from-latest-tag")
            .long("from-latest-tag")
            .help("uses the latest tag as starting point (ignores other --from parameters)")
            .mutually_excludes("from"))
        .get_matches();

    let start_nsec = time::get_time().nsec;

    let log_reader_config = LogReaderConfig {
        grep: "^feat|^fix|BREAKING'".to_owned(),
        format: "%H%n%s%n%b%n==END==".to_owned(),
        from: if matches.is_present("from-latest-tag") { Some(git::get_latest_tag()) } else { matches.value_of("from").map(|v| v.to_owned()) },
        to: matches.value_of("to").unwrap_or("").to_owned()
    };

    let commits = git::get_log_entries(log_reader_config);

    let sections = section_builder::build_sections(commits.clone());

    let mut contents = String::new();
    match File::open(&Path::new("changelog.md")).ok().expect("couldn't open changelog.md").read_to_string(&mut contents) {
        Ok(_) => (),
        Err(_) => contents = "".to_owned()
    }

    let mut file = File::create(&Path::new("changelog.md")).ok().unwrap();
    let mut writer = LogWriter::new(&mut file, LogWriterOptions {
        repository_link: matches.value_of("repository").unwrap(),
        version: if matches.is_present("setversion") {
                    matches.value_of("setversion").unwrap().to_owned()
                } else {
                    format_util::get_short_hash(&git::get_last_commit()[..]).to_owned()
                },
        subtitle: matches.value_of("subtitle").unwrap().to_owned()
    });

    writer.write_header().ok().expect("failed to write header");
    writer.write_section("Bug Fixes", &sections.fixes).ok().expect("failed to write bugfixes");;
    writer.write_section("Features", &sections.features).ok().expect("failed to write features");;
    writer.write(&contents[..]).ok().expect("failed to write contents");;

    let end_nsec = time::get_time().nsec;
    let elapsed_mssec = (end_nsec - start_nsec) / 1000000;
    println!("changelog updated. (took {} ms)", elapsed_mssec);
}
<commit_msg>fix(main): make --repository optional<commit_after>#![crate_name = "clog"]
#![feature(plugin)]
#![plugin(regex_macros)]

extern crate regex;
extern crate time;

extern crate clap;

use git::LogReaderConfig;
use log_writer::{ LogWriter, LogWriterOptions };
use std::fs::File;
use std::io::Read;
use std::path::Path;
use std::borrow::ToOwned;

use clap::{App, Arg};

mod common;
mod git;
mod log_writer;
mod section_builder;
mod format_util;

fn main () {
    // Pull version from Cargo.toml
    let version = format!("{}.{}.{}{}",
                          env!("CARGO_PKG_VERSION_MAJOR"),
                          env!("CARGO_PKG_VERSION_MINOR"),
                          env!("CARGO_PKG_VERSION_PATCH"),
                          option_env!("CARGO_PKG_VERSION_PRE").unwrap_or(""));
    let matches = App::new("clog")
        .version(&version[..])
        .about("a conventional changelog for the rest of us")
        .arg(Arg::new("repository")
            .short("r")
            .long("repository")
            .takes_value(true)
            .help("e.g. https://github.com/thoughtram/clog"))
        .arg(Arg::new("setversion")
            .long("setversion")
            .help("e.g. 1.0.1")
            .takes_value(true))
        .arg(Arg::new("subtitle")
            .long("subtitle")
            .help("e.g. crazy-release-title")
            .takes_value(true)
            .required(true))
        .arg(Arg::new("from")
            .help("e.g. 12a8546")
            .long("from")
            .takes_value(true))
        .arg(Arg::new("to")
            .long("to")
            .help("e.g. 8057684")
            .takes_value(true))
        .arg(Arg::new("from-latest-tag")
            .long("from-latest-tag")
            .help("uses the latest tag as starting point (ignores other --from parameters)")
            .mutually_excludes("from"))
        .get_matches();

    let start_nsec = time::get_time().nsec;

    let log_reader_config = LogReaderConfig {
        grep: "^feat|^fix|BREAKING'".to_owned(),
        format: "%H%n%s%n%b%n==END==".to_owned(),
        from: if matches.is_present("from-latest-tag") { Some(git::get_latest_tag()) } else { matches.value_of("from").map(|v| v.to_owned()) },
        to: matches.value_of("to").unwrap_or("").to_owned()
    };

    let commits = git::get_log_entries(log_reader_config);

    let sections = section_builder::build_sections(commits.clone());

    let mut contents = String::new();
    match File::open(&Path::new("changelog.md")).ok().expect("couldn't open changelog.md").read_to_string(&mut contents) {
        Ok(_) => (),
        Err(_) => contents = "".to_owned()
    }

    let mut file = File::create(&Path::new("changelog.md")).ok().unwrap();
    let mut writer = LogWriter::new(&mut file, LogWriterOptions {
        repository_link: matches.value_of("repository").unwrap_or(""),
        version: if matches.is_present("setversion") {
                    matches.value_of("setversion").unwrap().to_owned()
                } else {
                    format_util::get_short_hash(&git::get_last_commit()[..]).to_owned()
                },
        subtitle: matches.value_of("subtitle").unwrap().to_owned()
    });

    writer.write_header().ok().expect("failed to write header");
    writer.write_section("Bug Fixes", &sections.fixes).ok().expect("failed to write bugfixes");;
    writer.write_section("Features", &sections.features).ok().expect("failed to write features");;
    writer.write(&contents[..]).ok().expect("failed to write contents");;

    let end_nsec = time::get_time().nsec;
    let elapsed_mssec = (end_nsec - start_nsec) / 1000000;
    println!("changelog updated. (took {} ms)", elapsed_mssec);
}
<|endoftext|>